@NonNull
	protected final BluetoothGattCharacteristic characteristic(@NonNull final UUID uuid,
															   @CharacteristicProperties int properties,
															   @CharacteristicPermissions final int permissions,
															   @Nullable final byte[] initialValue,
															   final BluetoothGattDescriptor... descriptors) {
		// Look for Client Characteristic Configuration descriptor,
		// Characteristic User Description descriptor and Characteristic Extended Properties descriptor.
		boolean writableAuxiliaries = false;
		boolean cccdFound = false;
		boolean cepdFound = false;
		BluetoothGattDescriptor cepd = null;
		for (final BluetoothGattDescriptor descriptor : descriptors) {
			if (CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID.equals(descriptor.getUuid())) {
				cccdFound = true;
			} else if (CLIENT_USER_DESCRIPTION_DESCRIPTOR_UUID.equals(descriptor.getUuid())
					&& 0 != (descriptor.getPermissions() & (
							  BluetoothGattDescriptor.PERMISSION_WRITE
							| BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED
							| BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED_MITM))) {
				writableAuxiliaries = true;
			} else if (CHARACTERISTIC_EXTENDED_PROPERTIES_DESCRIPTOR_UUID.equals(descriptor.getUuid())) {
				cepd = descriptor;
				cepdFound = true;
			}
		}

		if (writableAuxiliaries) {
			if (cepd == null) {
				cepd = new BluetoothGattDescriptor(CHARACTERISTIC_EXTENDED_PROPERTIES_DESCRIPTOR_UUID,
						BluetoothGattDescriptor.PERMISSION_READ);
				cepd.setValue(new byte[]{0x02, 0x00});
			} else {
				if (cepd.getValue() != null && cepd.getValue().length == 2) {
					cepd.getValue()[0] |= 0x02;
				} else {
					cepd.setValue(new byte[]{0x02, 0x00});
				}
			}
		}

		final boolean cccdRequired = (properties & (BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_INDICATE)) != 0;
		final boolean reliableWrite = cepd != null && cepd.getValue() != null
				&& cepd.getValue().length == 2 && (cepd.getValue()[0] & 0x01) != 0;
		if (writableAuxiliaries || reliableWrite) {
			properties |= BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS;
		}
		if ((properties & BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS) != 0 && cepd == null) {
			cepd = new BluetoothGattDescriptor(CHARACTERISTIC_EXTENDED_PROPERTIES_DESCRIPTOR_UUID, BluetoothGattDescriptor.PERMISSION_READ);
			cepd.setValue(new byte[] { 0, 0 });
		}


		final BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(uuid, properties, permissions);
		if (cccdRequired && !cccdFound) {
			characteristic.addDescriptor(cccd());
		}
		for (BluetoothGattDescriptor descriptor: descriptors) {
			characteristic.addDescriptor(descriptor);
		}
		if (cepd != null && !cepdFound) {
			characteristic.addDescriptor(cepd);
		}
		characteristic.setValue(initialValue);
		return characteristic;
	}
A helper method that creates a characteristic with given UUID, properties and permissions.
Optionally, an initial value and a list of descriptors may be set.
<p>
The Client Characteristic Configuration Descriptor (CCCD) will be added automatically if
{@link BluetoothGattCharacteristic#PROPERTY_NOTIFY} or {@link BluetoothGattCharacteristic#PROPERTY_INDICATE}
was set, if not added explicitly in the descriptors list.
<p>
If {@link #reliableWrite()} was added as one of the descriptors or the Characteristic User
Description descriptor was created with any of write permissions
(see {@link #description(String, boolean)}) the
{@link BluetoothGattCharacteristic#PROPERTY_EXTENDED_PROPS} property will be added automatically.
<p>
The value of the characteristic will NOT be shared between clients. Each client will write
and read its own copy. To create a shared characteristic, use
{@link #sharedCharacteristic(UUID, int, int, byte[], BluetoothGattDescriptor...)} instead.

@param uuid The characteristic UUID.
@param properties The bit mask of characteristic properties. See {@link BluetoothGattCharacteristic}
                  for details.
@param permissions The bit mask or characteristic permissions. See {@link BluetoothGattCharacteristic}
                   for details.
@param initialValue The optional initial value of the characteristic.
@param descriptors The optional list of descriptors.
@return The characteristic.
ble/src/main/java/no/nordicsemi/android/ble/BleServerManager.java