| Index: content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc | 
| diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc | 
| index 968d0e8d35cd5dd8ef5ad5e8a33bda1c8efa0c1f..6e3a272867ba1070fc52828bda70dcb9b5f9907e 100644 | 
| --- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc | 
| +++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc | 
| @@ -97,6 +97,8 @@ const char kClientConfigUUID[] = "2902"; | 
| // Blocklisted descriptor | 
| const char kBlocklistedDescriptorUUID[] = | 
| "bad2ddcf-60db-45cd-bef9-fd72b153cf7c"; | 
| +const char kCharacteristicUserDescription[] = | 
| +    "gatt.characteristic_user_description"; | 
|  | 
| // Invokes Run() on the k-th argument of the function with no arguments. | 
| ACTION_TEMPLATE(RunCallback, | 
| @@ -160,7 +162,7 @@ void NotifyDeviceChanged(MockBluetoothAdapter* adapter, | 
| observer.DeviceChanged(adapter, device); | 
| } | 
|  | 
| -void PerformReadValue( | 
| +void PerformCharacteristicReadValue( | 
| MockBluetoothAdapter* adapter, | 
| MockBluetoothGattCharacteristic* characteristic, | 
| const BluetoothRemoteGattCharacteristic::ValueCallback& callback, | 
| @@ -171,6 +173,17 @@ void PerformReadValue( | 
| callback.Run(value); | 
| } | 
|  | 
| +void PerformDescriptorReadValue( | 
| +    MockBluetoothAdapter* adapter, | 
| +    MockBluetoothGattDescriptor* descriptor, | 
| +    const BluetoothRemoteGattDescriptor::ValueCallback& callback, | 
| +    const std::vector<uint8_t>& value) { | 
| +  for (auto& observer : adapter->GetObservers()) { | 
| +    observer.GattDescriptorValueChanged(adapter, descriptor, value); | 
| +  } | 
| +  callback.Run(value); | 
| +} | 
| + | 
| }  // namespace | 
|  | 
| namespace content { | 
| @@ -214,7 +227,10 @@ LayoutTestBluetoothAdapterProvider::GetBluetoothAdapter( | 
| if (fake_adapter_name == "DisconnectingHeartRateAdapter") | 
| return GetDisconnectingHeartRateAdapter(); | 
| if (fake_adapter_name == "DisconnectingHealthThermometerAdapter") | 
| -    return GetDisconnectingHealthThermometer(); | 
| +    return GetDisconnectingHealthThermometer(true); | 
| +  if (fake_adapter_name == | 
| +      "MissingDescriptorsDisconnectingHealthThermometerAdapter") | 
| +    return GetDisconnectingHealthThermometer(false); | 
| if (fake_adapter_name == "DisconnectingDuringServiceRetrievalAdapter") | 
| return GetServicesDiscoveredAfterReconnectionAdapter(true /* disconnect */); | 
| if (fake_adapter_name == "ServicesDiscoveredAfterReconnectionAdapter") | 
| @@ -666,7 +682,8 @@ LayoutTestBluetoothAdapterProvider::GetHeartRateAdapter() { | 
|  | 
| // static | 
| scoped_refptr<NiceMockBluetoothAdapter> | 
| -LayoutTestBluetoothAdapterProvider::GetDisconnectingHealthThermometer() { | 
| +LayoutTestBluetoothAdapterProvider::GetDisconnectingHealthThermometer( | 
| +    bool addDescriptors) { | 
| scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter()); | 
| NiceMockBluetoothAdapter* adapter_ptr = adapter.get(); | 
|  | 
| @@ -711,30 +728,41 @@ LayoutTestBluetoothAdapterProvider::GetDisconnectingHealthThermometer() { | 
| return GetBaseGATTNotifySession(measurement_ptr->GetWeakPtr()); | 
| })); | 
|  | 
| -  auto user_description = base::MakeUnique<NiceMockBluetoothGattDescriptor>( | 
| -      measurement_interval.get(), "gatt.characteristic_user_description", | 
| -      BluetoothUUID(kUserDescriptionUUID), false, | 
| -      device::BluetoothRemoteGattCharacteristic::PROPERTY_READ); | 
| - | 
| -  auto client_config = base::MakeUnique<NiceMockBluetoothGattDescriptor>( | 
| -      measurement_interval.get(), "gatt.client_characteristic_configuration", | 
| -      BluetoothUUID(kClientConfigUUID), false, | 
| -      device::BluetoothRemoteGattCharacteristic::PROPERTY_READ | | 
| -          device::BluetoothRemoteGattCharacteristic::PROPERTY_WRITE); | 
| - | 
| -  // Add it here with full permission as the blocklist should prevent us from | 
| -  // accessing this descriptor | 
| -  auto blocklisted_descriptor = | 
| -      base::MakeUnique<NiceMockBluetoothGattDescriptor>( | 
| -          measurement_interval.get(), "bad2ddcf-60db-45cd-bef9-fd72b153cf7c", | 
| -          BluetoothUUID(kBlocklistedDescriptorUUID), false, | 
| -          device::BluetoothRemoteGattCharacteristic::PROPERTY_READ | | 
| -              device::BluetoothRemoteGattCharacteristic::PROPERTY_WRITE); | 
| - | 
| -  measurement_interval->AddMockDescriptor(std::move(user_description)); | 
| -  measurement_interval->AddMockDescriptor(std::move(client_config)); | 
| -  measurement_interval->AddMockDescriptor(std::move(blocklisted_descriptor)); | 
| - | 
| +  if (addDescriptors == true) { | 
| +    std::string descriptorName = kCharacteristicUserDescription; | 
| +    auto user_description = base::MakeUnique<NiceMockBluetoothGattDescriptor>( | 
| +        measurement_interval.get(), descriptorName, | 
| +        BluetoothUUID(kUserDescriptionUUID), false, | 
| +        device::BluetoothRemoteGattCharacteristic::PROPERTY_READ); | 
| + | 
| +    ON_CALL(*user_description, ReadRemoteDescriptor(_, _)) | 
| +        .WillByDefault(Invoke([descriptorName]( | 
| +            const BluetoothRemoteGattDescriptor::ValueCallback& callback, | 
| +            const BluetoothRemoteGattDescriptor::ErrorCallback&) { | 
| +          std::vector<uint8_t> value(descriptorName.begin(), | 
| +                                     descriptorName.end()); | 
| +          callback.Run(value); | 
| +        })); | 
| + | 
| +    auto client_config = base::MakeUnique<NiceMockBluetoothGattDescriptor>( | 
| +        measurement_interval.get(), "gatt.client_characteristic_configuration", | 
| +        BluetoothUUID(kClientConfigUUID), false, | 
| +        device::BluetoothRemoteGattCharacteristic::PROPERTY_READ | | 
| +            device::BluetoothRemoteGattCharacteristic::PROPERTY_WRITE); | 
| + | 
| +    // Add it here with full permission as the blocklist should prevent us from | 
| +    // accessing this descriptor | 
| +    auto blocklisted_descriptor = | 
| +        base::MakeUnique<NiceMockBluetoothGattDescriptor>( | 
| +            measurement_interval.get(), "bad2ddcf-60db-45cd-bef9-fd72b153cf7c", | 
| +            BluetoothUUID(kBlocklistedDescriptorUUID), false, | 
| +            device::BluetoothRemoteGattCharacteristic::PROPERTY_READ | | 
| +                device::BluetoothRemoteGattCharacteristic::PROPERTY_WRITE); | 
| + | 
| +    measurement_interval->AddMockDescriptor(std::move(user_description)); | 
| +    measurement_interval->AddMockDescriptor(std::move(client_config)); | 
| +    measurement_interval->AddMockDescriptor(std::move(blocklisted_descriptor)); | 
| +  } | 
| health_thermometer->AddMockCharacteristic(std::move(measurement_interval)); | 
| device->AddMockService(std::move(health_thermometer)); | 
|  | 
| @@ -974,9 +1002,9 @@ scoped_refptr<NiceMockBluetoothAdapter> LayoutTestBluetoothAdapterProvider:: | 
| error_callback) { | 
| base::Closure pending; | 
| if (succeeds) { | 
| -          pending = | 
| -              base::Bind(&PerformReadValue, base::RetainedRef(adapter_ptr), | 
| -                         measurement_ptr, callback, std::vector<uint8_t>({1})); | 
| +          pending = base::Bind(&PerformCharacteristicReadValue, | 
| +                               base::RetainedRef(adapter_ptr), measurement_ptr, | 
| +                               callback, std::vector<uint8_t>({1})); | 
| } else { | 
| pending = base::Bind(error_callback, | 
| BluetoothRemoteGattService::GATT_ERROR_FAILED); | 
| @@ -1038,6 +1066,38 @@ scoped_refptr<NiceMockBluetoothAdapter> LayoutTestBluetoothAdapterProvider:: | 
| } | 
| })); | 
|  | 
| +  auto user_descriptor = base::MakeUnique<NiceMockBluetoothGattDescriptor>( | 
| +      measurement_interval.get(), kCharacteristicUserDescription, | 
| +      BluetoothUUID(kUserDescriptionUUID), false, | 
| +      device::BluetoothRemoteGattCharacteristic::PROPERTY_READ); | 
| + | 
| +  NiceMockBluetoothGattDescriptor* user_descriptor_ptr = user_descriptor.get(); | 
| +  ON_CALL(*user_descriptor, ReadRemoteDescriptor(_, _)) | 
| +      .WillByDefault(Invoke([adapter_ptr, device_ptr, user_descriptor_ptr, | 
| +                             disconnect, succeeds]( | 
| +          const BluetoothRemoteGattDescriptor::ValueCallback& callback, | 
| +          const BluetoothRemoteGattDescriptor::ErrorCallback& error_callback) { | 
| +        base::Closure pending; | 
| +        if (succeeds) { | 
| +          pending = base::Bind( | 
| +              &PerformDescriptorReadValue, base::RetainedRef(adapter_ptr), | 
| +              user_descriptor_ptr, callback, std::vector<uint8_t>({1})); | 
| +        } else { | 
| +          pending = base::Bind(error_callback, | 
| +                               BluetoothRemoteGattService::GATT_ERROR_FAILED); | 
| +        } | 
| +        device_ptr->PushPendingCallback(pending); | 
| +        if (disconnect) { | 
| +          device_ptr->SetConnected(false); | 
| +          base::ThreadTaskRunnerHandle::Get()->PostTask( | 
| +              FROM_HERE, | 
| +              base::Bind(&NotifyDeviceChanged, base::RetainedRef(adapter_ptr), | 
| +                         device_ptr)); | 
| +        } | 
| +      })); | 
| + | 
| +  measurement_interval->AddMockDescriptor(std::move(user_descriptor)); | 
| + | 
| health_thermometer->AddMockCharacteristic(std::move(measurement_interval)); | 
| device->AddMockService(std::move(health_thermometer)); | 
| adapter->AddMockDevice(std::move(device)); | 
| @@ -1626,6 +1686,17 @@ LayoutTestBluetoothAdapterProvider::GetErrorCharacteristic( | 
| ON_CALL(*characteristic, StartNotifySession(_, _)) | 
| .WillByDefault(RunCallback<1 /* error_callback */>(error_code)); | 
|  | 
| +  // Add error descriptor to |characteristic| | 
| +  auto error_descriptor = base::MakeUnique<NiceMockBluetoothGattDescriptor>( | 
| +      characteristic.get(), kCharacteristicUserDescription, | 
| +      BluetoothUUID(kUserDescriptionUUID), false, | 
| +      device::BluetoothRemoteGattCharacteristic::PROPERTY_READ); | 
| + | 
| +  ON_CALL(*error_descriptor, ReadRemoteDescriptor(_, _)) | 
| +      .WillByDefault(RunCallback<1 /* error_callback */>(error_code)); | 
| + | 
| +  characteristic->AddMockDescriptor(std::move(error_descriptor)); | 
| + | 
| return characteristic; | 
| } | 
|  | 
| @@ -1706,4 +1777,4 @@ std::string LayoutTestBluetoothAdapterProvider::makeMACAddress(uint64_t addr) { | 
| base::StringPrintf("%012" PRIx64, addr)); | 
| } | 
|  | 
| -}  // namespace content | 
| +}  // namespace content | 
|  |