Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions algorigoble2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ android {
dependencies {

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.startup:startup-runtime:1.1.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
Expand Down
14 changes: 14 additions & 0 deletions algorigoble2/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.algorigo.algorigoble2">

<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">

<meta-data
android:name="com.algorigo.algorigoble2.AlgorigoBleInitializer"
android:value="androidx.startup"
/>
</provider>
</application>

<!-- 블루투스 퍼미션 -->
<uses-feature
android:name="android.hardware.bluetooth_le"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.algorigo.algorigoble2

import android.content.Context
import androidx.startup.Initializer
import com.algorigo.algorigoble2.logging.DefaultLogger
import com.algorigo.algorigoble2.logging.Logging

object AlgorigoBleLibrary

internal lateinit var applicationContext: Context
private set

internal lateinit var logging: Logging

class AlgorigoBleInitializer: Initializer<AlgorigoBleLibrary> {

override fun create(context: Context): AlgorigoBleLibrary {
applicationContext = context.applicationContext
logging = Logging(DefaultLogger())
return AlgorigoBleLibrary
}

override fun dependencies(): MutableList<Class<out Initializer<*>>> = mutableListOf()
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.algorigo.algorigoble2

import android.bluetooth.BluetoothGattDescriptor
import com.algorigo.algorigoble2.logging.Logging
import java.util.*

open class BleDevice {
Expand All @@ -21,12 +20,10 @@ open class BleDevice {
}

internal lateinit var engine: BleDeviceEngine
internal lateinit var logging: Logging

internal fun initEngine(engine: BleDeviceEngine, logging: Logging) {
internal fun initEngine(engine: BleDeviceEngine) {
engine.bleDevice = this
this.engine = engine
this.logging = logging
}

val deviceId: String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.algorigo.algorigoble2

import android.bluetooth.BluetoothGattCharacteristic
import com.algorigo.algorigoble2.logging.Logging
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import java.util.UUID

internal abstract class BleDeviceEngine(protected val logging: Logging) {
abstract class BleDeviceEngine {

lateinit var bleDevice: BleDevice

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
package com.algorigo.algorigoble2

import android.bluetooth.BluetoothDevice
import android.content.Context
import com.algorigo.algorigoble2.impl.BleManagerEngineImpl
import com.algorigo.algorigoble2.logging.DefaultLogger
import com.algorigo.algorigoble2.logging.Logger
import com.algorigo.algorigoble2.logging.Logging
import com.algorigo.algorigoble2.virtual.VirtualDevice
import io.reactivex.rxjava3.core.Observable

class BleManager(
context: Context,
private val delegate: BleDeviceDelegate = defaultBleDeviceDelegate,
engine: Engine = Engine.ALGORIGO_BLE,
logger: Logger? = null,
virtualDevices: Array<Pair<VirtualDevice, BleDevice>> = arrayOf()
) {

Expand Down Expand Up @@ -49,14 +43,9 @@ class BleManager(
private val virtualDevices: Map<String, BleDevice>

init {
val logging = if (logger != null) {
Logging(logger)
} else {
Logging(DefaultLogger())
}
when (engine) {
// Engine.RX_ANDROID_BLE -> this.engine = RxAndroidBleEngine(context.applicationContext, delegate)
Engine.ALGORIGO_BLE -> this.engine = BleManagerEngineImpl(context.applicationContext, delegate, logging)
Engine.ALGORIGO_BLE -> this.engine = BleManagerEngineImpl(delegate)
}
this.virtualDevices = virtualDevices.associate {
Pair(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import com.algorigo.algorigoble2.virtual.VirtualDevice
import com.jakewharton.rxrelay3.PublishRelay
import io.reactivex.rxjava3.core.Observable

internal abstract class BleManagerEngine(protected val bleDeviceDelegate: BleManager.BleDeviceDelegate, protected val logging: Logging) {
internal abstract class BleManagerEngine(
protected val bleDeviceDelegate: BleManager.BleDeviceDelegate
) {

protected val connectionStateRelay = PublishRelay.create<Pair<BleDevice, BleDevice.ConnectionState>>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothGattService
import android.bluetooth.BluetoothProfile
import android.content.Context
import android.util.Log
import com.algorigo.algorigoble2.BleCharacterisic
import com.algorigo.algorigoble2.BleDevice
import com.algorigo.algorigoble2.BleDeviceEngine
import com.algorigo.algorigoble2.BleManager
import com.algorigo.algorigoble2.BleSppSocket
import com.algorigo.algorigoble2.logging.Logging
import com.algorigo.algorigoble2.applicationContext
import com.algorigo.algorigoble2.logging
import com.jakewharton.rxrelay3.BehaviorRelay
import com.jakewharton.rxrelay3.PublishRelay
import enumerated
Expand All @@ -29,8 +29,9 @@ import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException

@SuppressLint("MissingPermission")
internal class BleDeviceEngineImpl(private val context: Context, private val bluetoothDevice: BluetoothDevice, logging: Logging):
BleDeviceEngine(logging) {
internal class BleDeviceEngineImpl(
private val bluetoothDevice: BluetoothDevice
) : BleDeviceEngine() {

class CommunicationFailedException: Exception()
class IllegalCharacteristicProperty(val property: Int, val type: String): Exception()
Expand Down Expand Up @@ -268,7 +269,7 @@ internal class BleDeviceEngineImpl(private val context: Context, private val blu
if (it.second is State.DISCONNECTED) {
if (it.first == 0) {
logging.d { "${gatt?.device?.name}(${gatt?.device?.address}) : connectGatt call" }
gatt = bluetoothDevice.connectGatt(context, false, gattCallback)
gatt = bluetoothDevice.connectGatt(applicationContext, false, gattCallback)
stateRelay.accept(State.CONNECTING())
} else {
throw BleManager.DisconnectedException()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import androidx.core.location.LocationManagerCompat
import com.algorigo.algorigoble2.*
import com.algorigo.algorigoble2.exception.SystemServiceException
import com.algorigo.algorigoble2.extension.locationManager
import com.algorigo.algorigoble2.logging.Logging
import com.algorigo.algorigoble2.rx_util.RxBroadcastReceiver
import com.algorigo.algorigoble2.rx_util.collectListLastSortedIndex
import com.algorigo.algorigoble2.virtual.VirtualDevice
Expand All @@ -24,14 +23,16 @@ import io.reactivex.rxjava3.core.Observable
import java.util.*

@SuppressLint("MissingPermission")
internal class BleManagerEngineImpl(private val context: Context, bleDeviceDelegate: BleManager.BleDeviceDelegate, logging: Logging) : BleManagerEngine(bleDeviceDelegate, logging) {
internal class BleManagerEngineImpl(
bleDeviceDelegate: BleManager.BleDeviceDelegate
) : BleManagerEngine(bleDeviceDelegate) {

private val bluetoothManager: BluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val bluetoothManager: BluetoothManager = applicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter

private val deviceMap: MutableMap<BluetoothDevice, BleDevice> = mutableMapOf()

private val scanAvailableObservable = scanAvailableObservable(context)
private val scanAvailableObservable = scanAvailableObservable()
.doOnNext { (isLocationEnabled, isBluetoothEnabled) ->
if (!isLocationEnabled && isBluetoothEnabled) {
throw SystemServiceException.LocationUnavailableException("System location is unavailable")
Expand Down Expand Up @@ -63,14 +64,14 @@ internal class BleManagerEngineImpl(private val context: Context, bleDeviceDeleg
}

init {
context.registerReceiver(
applicationContext.registerReceiver(
bluetoothReceiver,
IntentFilter().apply { addAction(BluetoothAdapter.ACTION_STATE_CHANGED) }
)
}

protected fun finalize() {
context.unregisterReceiver(bluetoothReceiver)
applicationContext.unregisterReceiver(bluetoothReceiver)
}

override fun scanObservable(
Expand Down Expand Up @@ -149,40 +150,40 @@ internal class BleManagerEngineImpl(private val context: Context, bleDeviceDeleg
}
?.also { device ->
deviceMap[bluetoothDevice] = device
device.initEngine(BleDeviceEngineImpl(context, bluetoothDevice, logging), logging)
device.initEngine(BleDeviceEngineImpl(bluetoothDevice))
device.getConnectionStateObservable()
.subscribe({
connectionStateRelay.accept(Pair(device, it))
}, {})
}
}

private fun locationEnabledObservable(context: Context): Observable<Boolean> = when {
private fun locationEnabledObservable(): Observable<Boolean> = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> Observable.just(true)
else -> Observable
.fromCallable {
LocationManagerCompat.isLocationEnabled(context.locationManager)
LocationManagerCompat.isLocationEnabled(applicationContext.locationManager)
}
.concatWith(
RxBroadcastReceiver
.broadCastReceiverObservable(context, IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION))
.broadCastReceiverObservable(applicationContext, IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION))
.map { intent ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
intent.getBooleanExtra(LocationManager.EXTRA_PROVIDER_ENABLED, false)
} else {
LocationManagerCompat.isLocationEnabled(context.locationManager)
LocationManagerCompat.isLocationEnabled(applicationContext.locationManager)
}
}
)
}

private fun bluetoothEnabledObservable(context: Context): Observable<Boolean> {
private fun bluetoothEnabledObservable(): Observable<Boolean> {
return Observable
.fromCallable {
bluetoothAdapter.isEnabled
}
.concatWith(RxBroadcastReceiver
.broadCastReceiverObservable(context, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
.broadCastReceiverObservable(applicationContext, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
.map { intent -> intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) }
.map { state ->
when (state) {
Expand All @@ -195,19 +196,19 @@ internal class BleManagerEngineImpl(private val context: Context, bleDeviceDeleg
})
}

private fun scanAvailableObservable(context: Context): Observable<Pair<Boolean, Boolean>> {
private fun scanAvailableObservable(): Observable<Pair<Boolean, Boolean>> {
return Observable
.combineLatest(
locationEnabledObservable(context),
bluetoothEnabledObservable(context)
locationEnabledObservable(),
bluetoothEnabledObservable()
) { isLocationEnabled, isBluetoothEnabled ->
isLocationEnabled to isBluetoothEnabled
}
}

override fun initVirtualDevice(virtualDevice: VirtualDevice, bleDevice: BleDevice): BleDevice {
return bleDevice.also { device ->
device.initEngine(VirtualDeviceEngine(virtualDevice, logging), logging)
device.initEngine(VirtualDeviceEngine(virtualDevice))
device.getConnectionStateObservable()
.subscribe({
connectionStateRelay.accept(Pair(device, it))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import io.reactivex.rxjava3.core.Single
import java.util.*
import java.util.concurrent.TimeUnit

internal class VirtualDeviceEngine(private val virtualDevice: VirtualDevice, logging: Logging) : BleDeviceEngine(logging) {
internal class VirtualDeviceEngine(
private val virtualDevice: VirtualDevice
) : BleDeviceEngine() {
override val deviceId: String
get() = virtualDevice.deviceId
override val deviceName: String?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class BluetoothService : Service() {
override fun onCreate() {
super.onCreate()
bleManager = BleManager(
applicationContext,
virtualDevices = arrayOf(
VirtualBleDevice() to BleDevice(),
)
Expand Down