Example usage for android.bluetooth BluetoothGatt setCharacteristicNotification

List of usage examples for android.bluetooth BluetoothGatt setCharacteristicNotification

Introduction

In this page you can find the example usage for android.bluetooth BluetoothGatt setCharacteristicNotification.

Prototype

public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enable) 

Source Link

Document

Enable or disable notifications/indications for a given characteristic.

Usage

From source file:Main.java

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
static boolean setCharacteristicNotification(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
        boolean isEnabled) {
    if (characteristic != null) {
        gatt.setCharacteristicNotification(characteristic, isEnabled);
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(DEVICE_CONFIG_CHARACTERISTIC);
        if (descriptor != null) {
            descriptor.setValue(// www. ja v a  2s .c om
                    isEnabled ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : new byte[] { 0x00, 0x00 });
            return gatt.writeDescriptor(descriptor);
        } else
            return false;
    } else
        return false;
}

From source file:Main.java

public static boolean enableNotification(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    BluetoothGattDescriptor descriptor = configDescriptor(characteristic);
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
    return gatt.setCharacteristicNotification(characteristic, true) && gatt.writeDescriptor(descriptor);
}

From source file:Main.java

public static boolean disableNotification(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    BluetoothGattDescriptor descriptor = configDescriptor(characteristic);
    descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
    return gatt.writeDescriptor(descriptor) && gatt.setCharacteristicNotification(characteristic, false);
}

From source file:com.google.android.apps.forscience.ble.MyBleService.java

boolean setNotificationsFor(String address, BluetoothGattCharacteristic characteristic, boolean enable) {
    BluetoothGatt bluetoothGatt = addressToGattClient.get(address);
    if (bluetoothGatt == null) {
        Log.w(TAG, "No connection found for: " + address);
        return false;
    }// w  ww .j a  va2s.com

    return bluetoothGatt.setCharacteristicNotification(characteristic, enable);
}

From source file:ble.AndroidBle.java

@Override
public boolean characteristicNotification(String address, BleGattCharacteristic characteristic) {
    BleRequest request = mService.getCurrentRequest();
    BluetoothGatt gatt = mBluetoothGatts.get(address);
    if (gatt == null || characteristic == null) {
        return false;
    }/*from www  .  java  2s. co m*/

    boolean enable = true;
    if (request.type == RequestType.CHARACTERISTIC_STOP_NOTIFICATION) {
        enable = false;
    }
    BluetoothGattCharacteristic c = characteristic.getGattCharacteristicA();
    if (!gatt.setCharacteristicNotification(c, enable)) {
        return false;
    }

    BluetoothGattDescriptor descriptor = c.getDescriptor(BleService.DESC_CCC);
    if (descriptor == null) {
        return false;
    }

    byte[] val_set = null;
    if (request.type == RequestType.CHARACTERISTIC_NOTIFICATION) {
        val_set = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
    } else if (request.type == RequestType.CHARACTERISTIC_INDICATION) {
        val_set = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
    } else {
        val_set = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
    }
    if (!descriptor.setValue(val_set)) {
        return false;
    }

    return gatt.writeDescriptor(descriptor);
}

From source file:com.megster.cordova.rfduino.Peripheral.java

@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    Log.d(TAG, "gatt " + gatt);
    Log.d(TAG, "status " + status);
    super.onServicesDiscovered(gatt, status);

    BluetoothGattService service = gatt.getService(RFDUINO_SERVICE_UUID);
    Log.d(TAG, "service " + service);

    BluetoothGattCharacteristic receiveCharacteristic = service.getCharacteristic(RECEIVE_CHARACTERISTIC_UUID);
    sendCharacteristic = service.getCharacteristic(SEND_CHARACTERISTIC_UUID);
    disconnectCharacteristic = service.getCharacteristic(DISCONNECT_CHARACTERISTIC_UUID);

    if (receiveCharacteristic != null) {
        gatt.setCharacteristicNotification(receiveCharacteristic, true);

        BluetoothGattDescriptor receiveConfigDescriptor = receiveCharacteristic
                .getDescriptor(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID);
        if (receiveConfigDescriptor != null) {
            receiveConfigDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            gatt.writeDescriptor(receiveConfigDescriptor);
        } else {//from  w ww.  j a va 2  s .co  m
            LOG.e(TAG, "Receive Characteristic can not be configured.");
        }
    } else {
        LOG.e(TAG, "Receive Characteristic is missing.");
    }

    // call the success callback for connect
    PluginResult result = new PluginResult(PluginResult.Status.OK);
    result.setKeepCallback(true);
    connectCallback.sendPluginResult(result);
}

From source file:com.nbplus.iotapp.bluetooth.BluetoothLeService.java

/**
 * Enables or disables notification on a give characteristic.
 *
 * @param enabled If true, enable notification.  False otherwise.
 *///from w w  w  .  j  a  va  2  s .c  o m
public boolean setCharacteristicNotification(String address, String serviceUuid, String characteristicUuid,
        boolean enabled) {
    Log.d(TAG, "writeRemoteCharacteristic add = " + address + ", svc = " + serviceUuid + ", char = "
            + characteristicUuid);
    if (StringUtils.isEmptyString(address) || StringUtils.isEmptyString(serviceUuid)
            || StringUtils.isEmptyString(characteristicUuid)) {
        Log.w(TAG, "Unknown parameter");
        return false;
    }
    BluetoothGatt bluetoothGatt = mConnectedBluetoothGattMap.get(address);
    if (mBluetoothAdapter == null || bluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized");
        return false;
    }
    BluetoothGattService service = bluetoothGatt.getService(UUID.fromString(serviceUuid));
    if (service == null) {
        Log.w(TAG, "Service not found.");
        return false;
    }
    BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(characteristicUuid));
    if (characteristic == null) {
        Log.w(TAG, "characteristic not found.");
        return false;
    }

    bluetoothGatt.setCharacteristicNotification(characteristic, enabled);

    final int charaProp = characteristic.getProperties();
    if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
        BluetoothGattDescriptor descriptor = characteristic
                .getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
        if (descriptor != null) {
            Log.d(TAG, ">>>> ENABLE_NOTIFICATION_VALUE : " + characteristic.getUuid().toString());
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            bluetoothGatt.writeDescriptor(descriptor);

            return true;
        } else {
            return false;
        }
    } else if ((charaProp & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {
        BluetoothGattDescriptor descriptor = characteristic
                .getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
        if (descriptor != null) {
            Log.d(TAG, ">>>> ENABLE_INDICATION_VALUE : " + characteristic.getUuid().toString());
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
            bluetoothGatt.writeDescriptor(descriptor);

            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

From source file:no.nordicsemi.android.nrftoolbox.dfu.DfuService.java

/**
 * Enables or disables the notifications for given characteristic. This method is SYNCHRONOUS and wait until the
 * {@link BluetoothGattCallback#onDescriptorWrite(BluetoothGatt, BluetoothGattDescriptor, int)} will be called or the connection state will change from {@link #STATE_CONNECTED_AND_READY}. If
 * connection state will change, or an error will occur, an exception will be thrown.
 * /*from  w  w w  .  ja  v  a  2s  .co  m*/
 * @param gatt
 *            the GATT device
 * @param characteristic
 *            the characteristic to enable or disable notifications for
 * @param enable
 *            <code>true</code> to enable notifications, <code>false</code> to disable them
 * @throws DfuException
 * @throws UploadAbortedException
 */
private void setCharacteristicNotification(final BluetoothGatt gatt,
        final BluetoothGattCharacteristic characteristic, final boolean enable)
        throws DeviceDisconnectedException, DfuException, UploadAbortedException {
    if (mConnectionState != STATE_CONNECTED_AND_READY)
        throw new DeviceDisconnectedException("Unable to set notifications state", mConnectionState);
    mErrorState = 0;

    if (mNotificationsEnabled == enable)
        return;

    logi((enable ? "Enabling " : "Disabling") + " notifications...");

    // enable notifications locally
    gatt.setCharacteristicNotification(characteristic, enable);

    // enable notifications on the device
    final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG);
    descriptor.setValue(enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
            : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
    gatt.writeDescriptor(descriptor);

    // We have to wait until device gets disconnected or an error occur
    try {
        synchronized (mLock) {
            while ((mNotificationsEnabled != enable && mConnectionState == STATE_CONNECTED_AND_READY
                    && mErrorState == 0 && !mAborted) || mPaused)
                mLock.wait();
        }
    } catch (final InterruptedException e) {
        loge("Sleeping interrupted", e);
    }
    if (mAborted)
        throw new UploadAbortedException();
    if (mErrorState != 0)
        throw new DfuException("Unable to set notifications state", mErrorState);
    if (mConnectionState != STATE_CONNECTED_AND_READY)
        throw new DeviceDisconnectedException("Unable to set notifications state", mConnectionState);
}

From source file:com.wolkabout.hexiwear.service.BluetoothService.java

private void createGATT(final BluetoothDevice device) {
    bluetoothGatt = device.connectGatt(this, true, new BluetoothGattCallback() {
        @Override//  www  .  jav  a  2  s  .c o  m
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            isConnected = BluetoothProfile.STATE_CONNECTED == newState;
            if (isConnected) {
                Log.i(TAG, "GATT connected.");
                startForeground(442, getNotification(device));
                gatt.discoverServices();
            } else {
                Log.i(TAG, "GATT disconnected.");
                NotificationService_.intent(BluetoothService.this).stop();
                notificationManager.notify(442, getNotification(device));
                gatt.connect();
            }

            final Intent connectionStateChanged = new Intent(CONNECTION_STATE_CHANGED);
            connectionStateChanged.putExtra(CONNECTION_STATE, isConnected);
            sendBroadcast(connectionStateChanged);
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            Log.i(TAG, "Services discovered.");
            if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
                handleAuthenticationError(gatt);
                return;
            }

            discoverCharacteristics(gatt);
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
                int status) {
            Log.i(TAG, "Characteristic written: " + status);

            if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
                handleAuthenticationError(gatt);
                return;
            }

            final byte command = characteristic.getValue()[0];
            switch (command) {
            case WRITE_TIME:
                Log.i(TAG, "Time written.");
                final BluetoothGattCharacteristic batteryCharacteristic = readableCharacteristics
                        .get(Characteristic.BATTERY.getUuid());
                gatt.setCharacteristicNotification(batteryCharacteristic, true);
                for (BluetoothGattDescriptor descriptor : batteryCharacteristic.getDescriptors()) {
                    if (descriptor.getUuid().toString().startsWith("00002904")) {
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                        gatt.writeDescriptor(descriptor);
                    }
                }
                break;
            case WRITE_NOTIFICATION:
                Log.i(TAG, "Notification sent.");
                if (notificationsQueue.isEmpty()) {
                    Log.i(TAG, "Reading characteristics...");
                    readNextCharacteristics(gatt);
                } else {
                    Log.i(TAG, "writing next notification...");
                    alertIn.setValue(notificationsQueue.poll());
                    gatt.writeCharacteristic(alertIn);
                }
                break;
            default:
                Log.w(TAG, "No such ALERT IN command: " + command);
                break;
            }
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            readCharacteristic(gatt, Characteristic.MANUFACTURER);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                final BluetoothGattCharacteristic gattCharacteristic, int status) {
            if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
                handleAuthenticationError(gatt);
                return;
            }

            final String characteristicUuid = gattCharacteristic.getUuid().toString();
            final Characteristic characteristic = Characteristic.byUuid(characteristicUuid);
            switch (characteristic) {
            case MANUFACTURER:
                manufacturerInfo.manufacturer = gattCharacteristic.getStringValue(0);
                readCharacteristic(gatt, Characteristic.FW_REVISION);
                break;
            case FW_REVISION:
                manufacturerInfo.firmwareRevision = gattCharacteristic.getStringValue(0);
                readCharacteristic(gatt, Characteristic.MODE);
                break;
            default:
                Log.v(TAG, "Characteristic read: " + characteristic.name());
                if (characteristic == Characteristic.MODE) {
                    final Mode newMode = Mode.bySymbol(gattCharacteristic.getValue()[0]);
                    if (mode != newMode) {
                        onModeChanged(newMode);
                    }
                } else {
                    onBluetoothDataReceived(characteristic, gattCharacteristic.getValue());
                }

                if (notificationsQueue.isEmpty()) {
                    readNextCharacteristics(gatt);
                } else {
                    alertIn.setValue(notificationsQueue.poll());
                    gatt.writeCharacteristic(alertIn);
                }

                break;
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                BluetoothGattCharacteristic gattCharacteristic) {
            final String characteristicUuid = gattCharacteristic.getUuid().toString();
            final Characteristic characteristic = Characteristic.byUuid(characteristicUuid);
            Log.d(TAG, "Characteristic changed: " + characteristic);

            if (characteristic == Characteristic.BATTERY) {
                onBluetoothDataReceived(Characteristic.BATTERY, gattCharacteristic.getValue());
            }
        }
    });
}

From source file:no.nordicsemi.android.nrftoolbox.dfu.DfuService.java

@Override
protected void onHandleIntent(final Intent intent) {
    final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
    // In order to let DfuActivity know whether DFU is in progress, we have to use Shared Preferences 
    final SharedPreferences.Editor editor = preferences.edit();
    editor.putBoolean(PREFS_DFU_IN_PROGRESS, true);
    editor.commit();/*from  w  ww .  j  av  a 2s .  co  m*/

    initialize();

    final String deviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
    final String deviceName = intent.getStringExtra(EXTRA_DEVICE_NAME);
    final String filePath = intent.getStringExtra(EXTRA_FILE_PATH);
    final Uri fileUri = intent.getParcelableExtra(EXTRA_FILE_URI);
    final Uri logUri = intent.getParcelableExtra(EXTRA_LOG_URI);
    mLogSession = Logger.openSession(this, logUri);

    mDeviceAddress = deviceAddress;
    mDeviceName = deviceName;
    mConnectionState = STATE_DISCONNECTED;

    // read preferences
    final boolean packetReceiptNotificationEnabled = preferences
            .getBoolean(SettingsFragment.SETTINGS_PACKET_RECEIPT_NOTIFICATION_ENABLED, true);
    final String value = preferences.getString(SettingsFragment.SETTINGS_NUMBER_OF_PACKETS,
            String.valueOf(SettingsFragment.SETTINGS_NUMBER_OF_PACKETS_DEFAULT));
    int numberOfPackets = SettingsFragment.SETTINGS_NUMBER_OF_PACKETS_DEFAULT;
    try {
        numberOfPackets = Integer.parseInt(value);
        if (numberOfPackets < 0 || numberOfPackets > 0xFFFF)
            numberOfPackets = SettingsFragment.SETTINGS_NUMBER_OF_PACKETS_DEFAULT;
    } catch (final NumberFormatException e) {
        numberOfPackets = SettingsFragment.SETTINGS_NUMBER_OF_PACKETS_DEFAULT;
    }
    if (!packetReceiptNotificationEnabled)
        numberOfPackets = 0;
    mPacketsBeforeNotification = numberOfPackets;

    sendLogBroadcast(Level.VERBOSE, "Starting DFU service");

    HexInputStream his = null;
    try {
        // Prepare data to send, calculate stream size
        try {
            sendLogBroadcast(Level.VERBOSE, "Opening file...");
            if (fileUri != null)
                his = openInputStream(fileUri);
            else
                his = openInputStream(filePath);

            mImageSizeInBytes = his.sizeInBytes();
            mImageSizeInPackets = his.sizeInPackets(MAX_PACKET_SIZE);
            mHexInputStream = his;
            sendLogBroadcast(Level.INFO, "Image file opened (" + mImageSizeInBytes + " bytes)");
        } catch (final FileNotFoundException e) {
            loge("An exception occured while opening file", e);
            sendErrorBroadcast(ERROR_FILE_NOT_FOUND);
            return;
        } catch (final IOException e) {
            loge("An exception occured while calculating file size", e);
            sendErrorBroadcast(ERROR_FILE_CLOSED);
            return;
        }

        // Let's connect to the device
        sendLogBroadcast(Level.VERBOSE, "Connecting to DFU target...");
        updateProgressNotification(PROGRESS_CONNECTING);

        final BluetoothGatt gatt = connect(deviceAddress);
        // Are we connected?
        if (mErrorState > 0) { // error occurred
            final int error = mErrorState & ~ERROR_CONNECTION_MASK;
            loge("An error occurred while connecting to the device:" + error);
            sendLogBroadcast(Level.ERROR,
                    String.format("Connection failed (0x%02X): %s", error, GattError.parse(error)));
            terminateConnection(gatt, mErrorState);
            return;
        }
        if (mAborted) {
            logi("Upload aborted");
            sendLogBroadcast(Level.WARNING, "Upload aborted");
            terminateConnection(gatt, PROGRESS_ABORTED);
            return;
        }

        // We have connected to DFU device and services are discoverer
        final BluetoothGattService dfuService = gatt.getService(DFU_SERVICE_UUID); // there was a case when the service was null. I don't know why
        if (dfuService == null) {
            loge("DFU service does not exists on the device");
            sendLogBroadcast(Level.WARNING, "Connected. DFU Service not found");
            terminateConnection(gatt, ERROR_SERVICE_NOT_FOUND);
            return;
        }
        final BluetoothGattCharacteristic controlPointCharacteristic = dfuService
                .getCharacteristic(DFU_CONTROL_POINT_UUID);
        final BluetoothGattCharacteristic packetCharacteristic = dfuService.getCharacteristic(DFU_PACKET_UUID);
        if (controlPointCharacteristic == null || packetCharacteristic == null) {
            loge("DFU characteristics not found in the DFU service");
            sendLogBroadcast(Level.WARNING, "Connected. DFU Characteristics not found");
            terminateConnection(gatt, ERROR_CHARACTERISTICS_NOT_FOUND);
            return;
        }

        sendLogBroadcast(Level.INFO, "Connected. Services discovered");
        try {
            // enable notifications
            updateProgressNotification(PROGRESS_STARTING);
            setCharacteristicNotification(gatt, controlPointCharacteristic, true);
            sendLogBroadcast(Level.INFO, "Notifications enabled");

            try {
                // set up the temporary variable that will hold the responses
                byte[] response = null;

                // send Start DFU command to Control Point
                logi("Sending Start DFU command (Op Code = 1)");
                writeOpCode(gatt, controlPointCharacteristic, OP_CODE_START_DFU);
                sendLogBroadcast(Level.INFO, "DFU Start sent (Op Code 1) ");

                // send image size in bytes to DFU Packet
                logi("Sending image size in bytes to DFU Packet");
                writeImageSize(gatt, packetCharacteristic, mImageSizeInBytes);
                sendLogBroadcast(Level.INFO, "Firmware image size sent");

                // a notification will come with confirmation. Let's wait for it a bit
                response = readNotificationResponse();

                /*
                 * The response received from the DFU device contains:
                 * +---------+--------+----------------------------------------------------+
                 * | byte no |  value |                  description                       |
                 * +---------+--------+----------------------------------------------------+
                 * |       0 |     16 | Response code                                      |
                 * |       1 |      1 | The Op Code of a request that this response is for |
                 * |       2 | STATUS | See DFU_STATUS_* for status codes                  |
                 * +---------+--------+----------------------------------------------------+
                 */
                int status = getStatusCode(response, OP_CODE_RECEIVE_START_DFU_KEY);
                sendLogBroadcast(Level.INFO,
                        "Responce received (Op Code: " + response[1] + " Status: " + status + ")");
                if (status != DFU_STATUS_SUCCESS)
                    throw new RemoteDfuException("Starting DFU failed", status);

                // Send the number of packets of firmware before receiving a receipt notification
                final int numberOfPacketsBeforeNotification = mPacketsBeforeNotification;
                if (numberOfPacketsBeforeNotification > 0) {
                    logi("Sending the number of packets before notifications (Op Code = 8)");
                    setNumberOfPackets(OP_CODE_PACKET_RECEIPT_NOTIF_REQ, numberOfPacketsBeforeNotification);
                    writeOpCode(gatt, controlPointCharacteristic, OP_CODE_PACKET_RECEIPT_NOTIF_REQ);
                    sendLogBroadcast(Level.INFO, "Packet Receipt Notif Req (Op Code 8) sent (value: "
                            + mPacketsBeforeNotification + ")");
                }

                // Initialize firmware upload
                logi("Sending Receive Firmware Image request (Op Code = 3)");
                writeOpCode(gatt, controlPointCharacteristic, OP_CODE_RECEIVE_FIRMWARE_IMAGE);
                sendLogBroadcast(Level.INFO, "Receive Firmware Image request sent");

                // This allow us to calculate upload time
                final long startTime = System.currentTimeMillis();
                updateProgressNotification();
                try {
                    sendLogBroadcast(Level.INFO, "Starting upload...");
                    response = uploadFirmwareImage(gatt, packetCharacteristic, his);
                } catch (final DeviceDisconnectedException e) {
                    loge("Disconnected while sending data");
                    throw e;
                    // TODO reconnect?
                }

                final long endTime = System.currentTimeMillis();
                logi("Transfer of " + mBytesSent + " bytes has taken " + (endTime - startTime) + " ms");
                sendLogBroadcast(Level.INFO, "Upload completed in " + (endTime - startTime) + " ms");

                // Check the result of the operation
                status = getStatusCode(response, OP_CODE_RECEIVE_FIRMWARE_IMAGE_KEY);
                sendLogBroadcast(Level.INFO,
                        "Responce received (Op Code: " + response[1] + " Status: " + status + ")");
                logi("Response received. Op Code: " + response[0] + " Req Op Code: " + response[1] + " status: "
                        + response[2]);
                if (status != DFU_STATUS_SUCCESS)
                    throw new RemoteDfuException("Device returned error after sending file", status);

                // Send Validate request
                logi("Sending Validate request (Op Code = 4)");
                writeOpCode(gatt, controlPointCharacteristic, OP_CODE_VALIDATE);
                sendLogBroadcast(Level.INFO, "Validate request sent");

                // A notification will come with status code. Let's wait for it a bit.
                response = readNotificationResponse();
                status = getStatusCode(response, OP_CODE_RECEIVE_VALIDATE_KEY);
                sendLogBroadcast(Level.INFO,
                        "Responce received (Op Code: " + response[1] + " Status: " + status + ")");
                if (status != DFU_STATUS_SUCCESS)
                    throw new RemoteDfuException("Device returned validation error", status);

                // Disable notifications locally (we don't need to disable them on the device, it will reset)
                updateProgressNotification(PROGRESS_DISCONNECTING);
                gatt.setCharacteristicNotification(controlPointCharacteristic, false);
                sendLogBroadcast(Level.INFO, "Notifications disabled");

                // Send Activate and Reset signal.
                logi("Sending Activate and Reset request (Op Code = 5)");
                writeOpCode(gatt, controlPointCharacteristic, OP_CODE_ACTIVATE_AND_RESET);
                sendLogBroadcast(Level.INFO, "Activate and Reset request sent");

                // The device will reset so we don't have to send Disconnect signal.
                waitUntilDisconnected();
                sendLogBroadcast(Level.INFO, "Disconnected by remote device");

                // Close the device
                refreshDeviceCache(gatt);
                close(gatt);
                updateProgressNotification(PROGRESS_COMPLETED);
            } catch (final UnknownResponseException e) {
                final int error = ERROR_INVALID_RESPONSE;
                loge(e.getMessage());
                sendLogBroadcast(Level.ERROR, e.getMessage());

                // This causes GATT_ERROR 0x85 on Nexus 4 (4.4.2)
                //               logi("Sending Reset command (Op Code = 6)");
                //               writeOpCode(gatt, controlPointCharacteristic, OP_CODE_RESET);
                //               sendLogBroadcast(Level.INFO, "Reset request sent");
                terminateConnection(gatt, error);
            } catch (final RemoteDfuException e) {
                final int error = ERROR_REMOTE_MASK | e.getErrorNumber();
                loge(e.getMessage());
                sendLogBroadcast(Level.ERROR, String.format("Remote DFU error: %s", GattError.parse(error)));

                // This causes GATT_ERROR 0x85 on Nexus 4 (4.4.2)
                //               logi("Sending Reset command (Op Code = 6)");
                //               writeOpCode(gatt, controlPointCharacteristic, OP_CODE_RESET);
                //               sendLogBroadcast(Level.INFO, "Reset request sent");
                terminateConnection(gatt, error);
            }
        } catch (final UploadAbortedException e) {
            logi("Upload aborted");
            sendLogBroadcast(Level.WARNING, "Upload aborted");
            if (mConnectionState == STATE_CONNECTED_AND_READY)
                try {
                    mAborted = false;
                    logi("Sending Reset command (Op Code = 6)");
                    writeOpCode(gatt, controlPointCharacteristic, OP_CODE_RESET);
                    sendLogBroadcast(Level.INFO, "Reset request sent");
                } catch (final Exception e1) {
                    // do nothing
                }
            terminateConnection(gatt, PROGRESS_ABORTED);
        } catch (final DeviceDisconnectedException e) {
            sendLogBroadcast(Level.ERROR, "Device has disconneted");
            // TODO reconnect n times?
            loge(e.getMessage());
            if (mNotificationsEnabled)
                gatt.setCharacteristicNotification(controlPointCharacteristic, false);
            close(gatt);
            updateProgressNotification(ERROR_DEVICE_DISCONNECTED);
            return;
        } catch (final DfuException e) {
            final int error = e.getErrorNumber() & ~ERROR_CONNECTION_MASK;
            sendLogBroadcast(Level.ERROR, String.format("Error (0x%02X): %s", error, GattError.parse(error)));
            loge(e.getMessage());
            if (mConnectionState == STATE_CONNECTED_AND_READY)
                try {
                    logi("Sending Reset command (Op Code = 6)");
                    writeOpCode(gatt, controlPointCharacteristic, OP_CODE_RESET);
                } catch (final Exception e1) {
                    // do nothing
                }
            terminateConnection(gatt, e.getErrorNumber());
        }
    } finally {
        try {
            // upload has finished (success of fail)
            editor.putBoolean(PREFS_DFU_IN_PROGRESS, false);
            editor.commit();

            // ensure that input stream is always closed
            mHexInputStream = null;
            if (his != null)
                his.close();
            his = null;
        } catch (IOException e) {
            // do nothing
        }
    }
}