RxAndroidBLE не находит устройства на android 4.3 - PullRequest
0 голосов
/ 28 апреля 2018

Здравствуйте. Я использую RxAndroidBLE для обнаружения устройства BLE. На андроиде 6 >= все вроде бы работает нормально, но не на 4.3 устройстве. Мое приложение может только обнаружить желаемое устройство BLE только один раз при запуске. После того, как устройство было обнаружено, новых открытий больше нет, пока я не перезапущу приложение. Любой совет будет высоко оценен. Пример минимального (не) рабочего кода:

MainActivity

import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.util.Log
import com.polidea.rxandroidble.RxBleClient
import com.polidea.rxandroidble.exceptions.BleScanException
import com.polidea.rxandroidble.scan.ScanResult
import com.polidea.rxandroidble.scan.ScanSettings
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        startLeScan(applicationContext)
    }

    private var rxBleClient: RxBleClient? = null
    private var scanSubscription: Subscription? = null

    private var handler: Handler? = null
    private var timer: Timer? = null
    private var timerTask: TimerTask? = null
    private var delay: Int = 0

    private fun isScanning(): Boolean {
        return scanSubscription != null
    }

    fun startLeScan(context: Context) {
        rxBleClient = MyaPP.getRxBleClient(context)

        if (isScanning()) {
            scanSubscription?.unsubscribe()
        } else {
            scanSubscription = rxBleClient?.scanBleDevices(
                    com.polidea.rxandroidble.scan.ScanSettings.Builder()
                            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
                            .build())
                    ?.observeOn(AndroidSchedulers.mainThread())
                    //?.doOnNext(this::newDevicesFound)
                    ?.doOnUnsubscribe(this::clearSubscription)
                    ?.subscribe(this::newDevicesFound, this::onScanFailure)
        }

        if(handler == null) {
            handler = Handler()
            timer = Timer(false)
            timerTask = object : TimerTask() {
                override fun run() {
                    handler?.post {
                        if (delay > 7) {
                            delay = 0

                            val service = Executors.newSingleThreadExecutor()
                            service.submit(Runnable {

                                //startLeScan(context)
                            })

                        } else {
                            delay = delay + 1
                        }
                    }
                }
            }
            timer?.scheduleAtFixedRate(timerTask, 0, 300)
        }
    }

    private fun newDevicesFound(devices: ScanResult) {
        Log.d("WHYY??", devices.bleDevice.name)
    }

    fun stopScan() {
        scanSubscription?.unsubscribe()
        destroy()
    }

    private fun clearSubscription() {
        scanSubscription = null
    }

    private fun onScanFailure(throwable: Throwable) {
        if (throwable is BleScanException) {
            handleBleScanException(throwable)
        }
    }

    private fun handleBleScanException(bleScanException: BleScanException) {
        val text: String

        when (bleScanException.reason) {
            BleScanException.BLUETOOTH_NOT_AVAILABLE -> text = "Bluetooth is not available"
            BleScanException.BLUETOOTH_DISABLED -> text = "Enable bluetooth and try again"
            BleScanException.LOCATION_PERMISSION_MISSING -> text = "On Android 6.0 location permission is required. Implement Runtime Permissions"
            BleScanException.LOCATION_SERVICES_DISABLED -> text = "Location services needs to be enabled on Android 6.0"
            BleScanException.SCAN_FAILED_ALREADY_STARTED -> text = "Scan with the same filters is already started"
            BleScanException.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED -> text = "Failed to register application for bluetooth scan"
            BleScanException.SCAN_FAILED_FEATURE_UNSUPPORTED -> text = "Scan with specified parameters is not supported"
            BleScanException.SCAN_FAILED_INTERNAL_ERROR -> text = "Scan failed due to internal error"
            BleScanException.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES -> text = "Scan cannot start due to limited hardware resources"
            BleScanException.UNDOCUMENTED_SCAN_THROTTLE -> text = String.format(
                    Locale.getDefault(),
                    "Android 7+ does not allow more scans. Try in %d seconds",
                    secondsTill(bleScanException.retryDateSuggestion)
            )
            BleScanException.UNKNOWN_ERROR_CODE, BleScanException.BLUETOOTH_CANNOT_START -> text = "Unable to start scanning"
            else -> text = "Unable to start scanning"
        }
        Log.w("EXCEPTION", text, bleScanException)
    }

    private fun secondsTill(retryDateSuggestion: Date?): Long {
        if (retryDateSuggestion != null) {
            return TimeUnit.MILLISECONDS.toSeconds(retryDateSuggestion.time - System.currentTimeMillis())
        }

        return 0
    }

    private fun destroy() {
        timer?.cancel()
        handler?.removeCallbacks(timerTask)
        handler = null
        timerTask = null
        timer = null
    }
}

MYAPP

import android.app.Application
import android.content.Context
import com.polidea.rxandroidble.RxBleClient
import com.polidea.rxandroidble.internal.RxBleLog


class MyaPP: Application() {

    private var rxBleClient: RxBleClient? = null

    companion object {
        fun getRxBleClient(context: Context): RxBleClient? {
            val application = context.applicationContext as MyaPP
            return application.rxBleClient
        }
    }

    override fun onCreate() {
        super.onCreate()

        rxBleClient = RxBleClient.create(this)
        RxBleClient.setLogLevel(RxBleLog.DEBUG)
    }
}

build.gradle

compile "com.polidea.rxandroidble:rxandroidble:1.5.0"
implementation 'io.reactivex:rxandroid:1.2.1'

манифест

<application
        android:name=".MyaPP"

1 Ответ

0 голосов
/ 07 мая 2018

Ваш код очень похож на пример приложения библиотеки (версия 1.5.0, ветка master-rxjava1). Я проверил это недавно на Android 4.4.4, который является самым старым, который у меня есть, и он работал нормально. Не было никаких изменений API между 4.3 и 4.4.

Возможно, вы испытываете поведение, характерное для вашего устройства (не стесняйтесь поделиться моделью телефона), при котором оно выполняет только обратные вызовы при первом сканировании определенного периферийного устройства. На эту тему уже есть некоторые темы, например this .

...