From f9437900ac2893fe4e2e467ceb9d9d04e10cdba2 Mon Sep 17 00:00:00 2001 From: Martin Williams Date: Tue, 9 Jul 2024 13:21:27 +0100 Subject: [PATCH] Pair - wait for disconnect; Flash - restart after bonding --- .../microbit/ui/activity/PairingActivity.java | 2 + .../microbit/ui/activity/ProjectActivity.java | 14 ++- .../com/samsung/microbit/utils/BLEPair.java | 103 +++++++++++++++--- app/src/main/res/values/strings.xml | 1 + pfLibrary | 2 +- 5 files changed, 104 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/samsung/microbit/ui/activity/PairingActivity.java b/app/src/main/java/com/samsung/microbit/ui/activity/PairingActivity.java index 573e48f5..6754ff3a 100644 --- a/app/src/main/java/com/samsung/microbit/ui/activity/PairingActivity.java +++ b/app/src/main/java/com/samsung/microbit/ui/activity/PairingActivity.java @@ -255,6 +255,8 @@ public void run() { popupPairingFailed(); } break; + case AlreadyPaired: + // micro:bit seems to need reset even if already paired case Paired: handlePairingSuccessful(); break; diff --git a/app/src/main/java/com/samsung/microbit/ui/activity/ProjectActivity.java b/app/src/main/java/com/samsung/microbit/ui/activity/ProjectActivity.java index c411caef..984d22ea 100644 --- a/app/src/main/java/com/samsung/microbit/ui/activity/ProjectActivity.java +++ b/app/src/main/java/com/samsung/microbit/ui/activity/ProjectActivity.java @@ -239,7 +239,7 @@ protected void onActivityResultPairing(int requestCode, int resultCode, Intent d case REQUEST_CODE_PAIR_BEFORE_FLASH_ALREADY_RESET: if (resultCode == RESULT_OK) { // micro:bit should still be in Bluetooth mode - flashingChecks( true); + flashingChecks( false); } else { onFlashComplete(); } @@ -2094,7 +2094,6 @@ public void onClick(View v) { } }, popupClickFlashComplete); } else if(intent.getAction().equals(PartialFlashingService.BROADCAST_ERROR)) { - MBApp.getAppState().eventPairSendError(); final int errorCode = intent.getIntExtra(PartialFlashingService.EXTRA_DATA, 0); String error_message = getString(R.string.connection_failed); @@ -2108,9 +2107,16 @@ public void onClick(View v) { case PartialFlashingService.ERROR_DFU_MODE: error_message = getString(R.string.reset_to_dfu_mode_failed); break; + case PartialFlashingService.ERROR_BROKEN: + error_message = getString(R.string.connection_broken); + break; + case PartialFlashingService.ERROR_BONDED: + restartPurpose(); + return; } logi("PFResultReceiver.onReceive() :: " + error_message + " code " + errorCode); + MBApp.getAppState().eventPairSendError(); PopUp.show( error_message + "\n\n" + getString(R.string.retry), getString(R.string.flashing_failed_title), @@ -2400,6 +2406,10 @@ public void onClick(View v) { error_message = getString(R.string.dfu_error_CODE, error_message); break; default: + if ( errorCode == DfuBaseService.ERROR_DEVICE_NOT_BONDED) { + restartPurpose(); + return; + } if ( errorCode == 0) { error_message = getString(R.string.not_found); } else { diff --git a/app/src/main/java/com/samsung/microbit/utils/BLEPair.java b/app/src/main/java/com/samsung/microbit/utils/BLEPair.java index 9c2b6eea..d43bd6e3 100644 --- a/app/src/main/java/com/samsung/microbit/utils/BLEPair.java +++ b/app/src/main/java/com/samsung/microbit/utils/BLEPair.java @@ -62,13 +62,16 @@ public class BLEPair implements BluetoothAdapter.LeScanCallback { // Android 13 - I have seen 4 status 133s before a good connect and pair private int pairChecks = 0; private int pairTries = 0; - private Boolean scanning = false; - private Boolean pairing = false; + private boolean scanning = false; + private boolean pairing = false; + private boolean waitingForDisconnect = false; + private boolean wasNotBonded = false; public enum enumResult { None, Found, Connected, + AlreadyPaired, Paired, TimeoutScan, TimeoutConnect, @@ -165,16 +168,49 @@ private void signalProgress( enumResult state) { } @SuppressLint("MissingPermission") - private void signalResultPairedIfBondedAndHardwareVersionDiscovered() { - if (resultDevice.getBondState() == BluetoothDevice.BOND_BONDED) { - // Wait for service discovery to set resultHardwareVersion - logi("Bonded resultHardwareVersion " + resultHardwareVersion); - if ( resultHardwareVersion > 0) { - signalResult(enumResult.Paired); - } + private boolean bondedAndHardwareVersionDiscovered() { + logi("bondedAndHardwareVersionDiscovered state " + resultDevice.getBondState() + " resultHardwareVersion " + resultHardwareVersion); + if ( resultDevice.getBondState() != BluetoothDevice.BOND_BONDED) { + wasNotBonded = true; + return false; + } + // Wait for service discovery to set resultHardwareVersion + if ( resultHardwareVersion <= 0) { + return false; + } + return true; + } + + @SuppressLint("MissingPermission") + private boolean startWaitingForDisconnectIfBondedAndHardwareVersionDiscovered() { + if ( !bondedAndHardwareVersionDiscovered()) { + return false; } + // Wait for micro:bit to disconnect + waitingForDisconnect = true; + delayStopAll(); + delayStart( delayCallbackWaitingForDisconnect, 6000); + logi("Start waiting for disconnect"); + return true; } + private void onDisconnect() { + // If actually pairing, micro:bit will break the connection + // Allow time for tick to appear + logi("onDisconnect"); + if ( bondedAndHardwareVersionDiscovered()) { + delayStopAll(); + delayStart( delayCallbackSignalResultPaired, 300); + } else if ( waitingForDisconnect) { + delayStopAll(); + delayStart( delayCallbackSignalResultPaired, 300); + } else { + logi("ERROR - disconnected"); + logi("Prepare delayed retry"); + gattState = enumGattState.Error; + delayStart( delayCallbackConnect, 1000); + } + } private void logi(String message) { if(DEBUG) { Log.i(TAG, "### " + Thread.currentThread().getId() + " # " + message); @@ -248,13 +284,15 @@ public void run() { } } }; - + private final Runnable delayCallbackCheck = new Runnable() { @Override public void run() { logi("delayCallbackCheck pairChecks " + pairChecks); if (pairing) { - signalResultPairedIfBondedAndHardwareVersionDiscovered(); + if ( startWaitingForDisconnectIfBondedAndHardwareVersionDiscovered()) { + return; + } if ( pairChecks > 0) { // We are connected and polling for bonding pairChecks -= 1; @@ -266,6 +304,22 @@ public void run() { } }; + private final Runnable delayCallbackWaitingForDisconnect = new Runnable() { + @Override + public void run() { + logi("delayCallbackWaitingForDisconnect wasNotBonded = " + wasNotBonded); + signalResult( wasNotBonded ? enumResult.Paired : enumResult.AlreadyPaired); + } + }; + + private final Runnable delayCallbackSignalResultPaired = new Runnable() { + @Override + public void run() { + logi("delayCallbackSignalResultPaired wasNotBonded = " + wasNotBonded); + signalResult( wasNotBonded ? enumResult.Paired : enumResult.AlreadyPaired); + } + }; + private void delayStopAll() { logi("delayStopAll"); @@ -275,6 +329,8 @@ private void delayStopAll() mainLooperHandler.removeCallbacks( delayCallbackDiscover); mainLooperHandler.removeCallbacks( delayCallbackBond); mainLooperHandler.removeCallbacks( delayCallbackCheck); + mainLooperHandler.removeCallbacks( delayCallbackWaitingForDisconnect); + mainLooperHandler.removeCallbacks( delayCallbackSignalResultPaired); } private void delayStop( Runnable callback) @@ -460,8 +516,17 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState return; } + if ( gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDED) { + wasNotBonded = true; + } + logi("onConnectionStateChange " + newState + " status " + status); - if ( status != 0) { + if ( status != BluetoothGatt.GATT_SUCCESS) { + if ( newState == STATE_DISCONNECTED) { + onDisconnect(); + return; + } + delayStopAll(); pairStop(); logi("ERROR - status"); logi("Prepare for retry after a short delay"); @@ -487,6 +552,7 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState // about 600ms after establishing connection. Values 600 - 1600ms should be OK. } else { logi("calling discoverServices()"); + wasNotBonded = true; gattState = enumGattState.WaitingForServices; boolean success = gatt.discoverServices(); if (!success) { @@ -502,7 +568,7 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState else if( newState == STATE_DISCONNECTED) { // If actually pairing, micro:bit will break the connection logi("STATE_DISCONNECTED"); - delayStartCheck(); + onDisconnect(); } } @@ -537,7 +603,10 @@ public void onServicesDiscovered(BluetoothGatt gatt, int status) { gattState = enumGattState.ServicesDiscovered; - if (resultDevice.getBondState() == BluetoothDevice.BOND_NONE) { + if ( startWaitingForDisconnectIfBondedAndHardwareVersionDiscovered()) + return; + + if ( resultDevice.getBondState() == BluetoothDevice.BOND_NONE) { logi("Delay calling createBond() to wait for bonding to start automatically"); delayStart( delayCallbackBond, 1500); } @@ -571,6 +640,7 @@ private Boolean pairConnect() { paramCallback.BLEPairGetActivity().registerReceiver( pairReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)); + waitingForDisconnect = false; resultHardwareVersion = 0; gattState = enumGattState.Connecting; pairing = true; @@ -643,13 +713,16 @@ public void onReceive(Context context, Intent intent) { final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR); final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR); logi("pairReceiver -" + " name = " + name + " addr = " + addr + " state = " + state + " prevState = " + prevState); + if ( state != BluetoothDevice.BOND_BONDED && prevState != BluetoothDevice.BOND_BONDED) { + wasNotBonded = true; + } if (name == null || name.isEmpty() || addr.isEmpty()) { return; } // Check the changed device is the one we are trying to pair if ( pairing && nameIsMicrobitWithCode(device.getName(), paramCallback.BLEPairGetDeviceCode())) { if (state == BluetoothDevice.BOND_BONDED) { - signalResultPairedIfBondedAndHardwareVersionDiscovered(); + startWaitingForDisconnectIfBondedAndHardwareVersionDiscovered(); } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5a4c437b..47db852e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -395,6 +395,7 @@ Unable to connect Unable to reconnect Unable to reset to DFU mode + Connection lost Retry? Import Export diff --git a/pfLibrary b/pfLibrary index 3816074e..5798672f 160000 --- a/pfLibrary +++ b/pfLibrary @@ -1 +1 @@ -Subproject commit 3816074e0a158f29a7667cd6b05a4258501e5e61 +Subproject commit 5798672fc0384adf972045a0942cbf5b42b8c10a