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 @@
</activity>
<activity
android:name=
".ScanActivity"
/>
<activity
android:name=
".SendActivity"
/>
</application>
<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
import
android.bluetooth.BluetoothGatt
import
android.bluetooth.BluetoothGattCharacteristic
import
android.bluetooth.BluetoothGattDescriptor
import
android.os.Environment
import
android.util.Log
import
java.io.BufferedInputStream
import
java.io.File
import
java.io.FileInputStream
import
java.nio.ByteBuffer
import
java.util.*
import
java.util.zip.CRC32
private
const
val
TAG
=
"FileTransfer"
class
FileTransfer
(
private
val
gatt
:
BluetoothGatt
,
private
val
dataCharacteristic
:
BluetoothGattCharacteristic
,
private
val
tx
:
BluetoothGattCharacteristic
,
private
val
rx
:
BluetoothGattCharacteristic
,
private
val
mtu
:
Int
)
{
private
val
filePath
=
"/Download/SEND.txt"
...
...
@@ -18,6 +25,9 @@ class FileTransfer(
private
val
iterator
=
openFile
().
iterator
()
private
var
offset
:
Int
=
0
private
var
lastCrc
:
Long
=
0
private
fun
openFile
():
ByteArray
{
// TODO: Don't listen to Android Docs, use stuff that is not deprecated
val
file
=
File
(
...
...
@@ -40,16 +50,15 @@ class FileTransfer(
}
fun
sendNext
()
{
Log
.
d
(
TAG
,
"Sending next chunk: $offset"
)
if
(!
iterator
.
hasNext
())
{
return
}
gatt
?.
beginReliableWrite
()
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
())
}
...
...
@@ -61,12 +70,18 @@ class FileTransfer(
val
sendBuffer
=
ByteBuffer
.
allocate
(
chunk
.
size
+
4
)
sendBuffer
.
putInt
(
header
)
sendBuffer
.
put
(
chunk
.
toByteArray
())
val
bytes
=
sendBuffer
.
array
()
val
crc
=
CRC32
()
crc
.
update
(
bytes
)
lastCrc
=
crc
.
value
dataCharacteristic
?.
value
=
sendBuffer
.
array
()
gatt
?.
writeCharacteristic
(
dataCharacteristic
)
// gatt?.beginReliableWrite()
tx
?.
value
=
bytes
val
status
=
gatt
?.
writeCharacteristic
(
tx
)
// This will trigger the onCharacteristicWrite callback once the other side ACKs
// In there, we can call the actual gatt?.executeReliableWrite()
if
(!
status
)
{
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"
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
connected
=
false
...
...
@@ -55,102 +39,4 @@ class MainActivity : AppCompatActivity() {
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"
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
listAdapter
:
DeviceListAdapter
...
...
@@ -32,6 +37,16 @@ class ScanActivity : AppCompatActivity() {
listAdapter
=
DeviceListAdapter
(
applicationContext
)
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
()
scan
()
}
...
...
@@ -47,13 +62,6 @@ class ScanActivity : AppCompatActivity() {
val
foundDevices
=
mutableSetOf
<
BluetoothDevice
>()
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
))
{
foundDevices
.
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 @@
android:layout_width=
"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>
\ 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