Commit 45215dac authored by Harry Cutts's avatar Harry Cutts Committed by Commit Bot

Add `SetProperty` to gesture props D-Bus service

See go/cros-gesture-properties-dbus-design (Google internal only, sorry)
for more details about the full design.

Bug: 952054
Test: call the `GetProperty` method with a command like this
(substituting a valid device ID):
    dbus-send --print-reply --system \
        --dest=org.chromium.GesturePropertiesService \
        /org/chromium/GesturePropertiesService \
        org.chromium.GesturePropertiesServiceInterface.SetProperty \
        int32:"$DEVICE_ID" string:"Mouse CPI" array:double:500

Change-Id: Ib91995c3c1fadbf776e55f078a35c38ced984020
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1589450
Commit-Queue: Harry Cutts <hcutts@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#678486}
parent 9209c3b7
......@@ -45,6 +45,12 @@ void GesturePropertiesServiceProvider::Start(
base::BindRepeating(&GesturePropertiesServiceProvider::GetProperty,
weak_ptr_factory_.GetWeakPtr()),
on_exported);
exported_object->ExportMethod(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceSetPropertyMethod,
base::BindRepeating(&GesturePropertiesServiceProvider::SetProperty,
weak_ptr_factory_.GetWeakPtr()),
on_exported);
}
void GesturePropertiesServiceProvider::OnExported(
......@@ -129,6 +135,41 @@ void GetPropertyCallback(
response_sender.Run(std::move(response));
}
void SetPropertyCallback(
dbus::MethodCall* method_call,
const dbus::ExportedObject::ResponseSender& response_sender,
ui::ozone::mojom::SetGesturePropErrorCode error) {
std::string error_message;
switch (error) {
case ui::ozone::mojom::SetGesturePropErrorCode::SUCCESS:
response_sender.Run(dbus::Response::FromMethodCall(method_call));
return;
case ui::ozone::mojom::SetGesturePropErrorCode::NOT_FOUND:
error_message = "The device ID or property name specified was not found.";
break;
case ui::ozone::mojom::SetGesturePropErrorCode::READ_ONLY:
error_message = "That property is read-only.";
break;
case ui::ozone::mojom::SetGesturePropErrorCode::TYPE_MISMATCH:
error_message =
"The property is of a different type than the value(s) "
"provided.";
break;
case ui::ozone::mojom::SetGesturePropErrorCode::SIZE_MISMATCH:
error_message =
"The property has a different number of values to that "
"provided.";
break;
case ui::ozone::mojom::SetGesturePropErrorCode::UNKNOWN_ERROR:
default:
error_message = "An unknown error occurred.";
break;
}
LOG(ERROR) << "SetProperty error: " << error_message;
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS, error_message));
}
void ListDevicesCallback(
std::unique_ptr<dbus::Response> response,
const dbus::ExportedObject::ResponseSender& response_sender,
......@@ -214,6 +255,104 @@ void GesturePropertiesServiceProvider::GetProperty(
response_sender));
}
static ui::ozone::mojom::GesturePropValuePtr GesturePropValueFromVariant(
dbus::MessageReader* variant_reader,
std::string* error_message) {
std::string string_value;
if (variant_reader->PopString(&string_value)) {
return ui::ozone::mojom::GesturePropValue::NewStr(string_value);
}
dbus::MessageReader array_reader(nullptr);
if (!variant_reader->PopArray(&array_reader)) {
*error_message =
"Value(s) should be specified either as a string or an "
"array of the appropriate type.";
return nullptr;
}
switch (array_reader.GetDataType()) {
case dbus::Message::DataType::INT32: {
std::vector<int32_t> values = {};
int32_t value;
while (array_reader.PopInt32(&value)) {
values.push_back(value);
}
return ui::ozone::mojom::GesturePropValue::NewInts(values);
}
case dbus::Message::DataType::INT16: {
std::vector<int16_t> values = {};
int16_t value;
while (array_reader.PopInt16(&value)) {
values.push_back(value);
}
return ui::ozone::mojom::GesturePropValue::NewShorts(values);
}
case dbus::Message::DataType::BOOL: {
std::vector<bool> values = {};
bool value;
while (array_reader.PopBool(&value)) {
values.push_back(value);
}
return ui::ozone::mojom::GesturePropValue::NewBools(values);
}
case dbus::Message::DataType::DOUBLE: {
std::vector<double> values = {};
double value;
while (array_reader.PopDouble(&value)) {
values.push_back(value);
}
return ui::ozone::mojom::GesturePropValue::NewReals(values);
}
case dbus::Message::DataType::STRING: {
*error_message =
"String properties can only have one value, and so "
"should not be specified as arrays.";
return nullptr;
}
default: {
*error_message =
"Unsupported D-Bus value type; supported types are "
"int32, int16, bool, double, and string.";
return nullptr;
}
}
}
void GesturePropertiesServiceProvider::SetProperty(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
dbus::MessageReader reader(method_call);
int32_t device_id;
std::string property_name;
if (!reader.PopInt32(&device_id) || !reader.PopString(&property_name)) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS,
"The device ID (int32) and/or property name (string) is missing."));
return;
}
if (!reader.HasMoreData()) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS, "No value(s) specified."));
return;
}
std::string error_message;
ui::ozone::mojom::GesturePropValuePtr values =
GesturePropValueFromVariant(&reader, &error_message);
if (values.is_null()) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS, error_message));
return;
}
GetService()->SetProperty(
device_id, property_name, std::move(values),
base::BindOnce(&SetPropertyCallback, method_call, response_sender));
}
ui::ozone::mojom::GesturePropertiesService*
GesturePropertiesServiceProvider::GetService() {
if (service_for_test_ != nullptr)
......
......@@ -59,6 +59,10 @@ class ASH_EXPORT GesturePropertiesServiceProvider
void GetProperty(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
// Called on UI thread in response to a D-Bus request.
void SetProperty(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
ui::ozone::mojom::GesturePropertiesService* GetService();
ui::ozone::mojom::GesturePropertiesServicePtr service_;
......
......@@ -73,6 +73,10 @@ class GesturePropertiesServiceProviderTest : public testing::Test {
ON_CALL(*mock_service_, GetProperty(_, _, _))
.WillByDefault(Invoke(
this, &GesturePropertiesServiceProviderTest::FakeGetProperty));
ON_CALL(*mock_service_, SetProperty(_, _, _, _))
.WillByDefault(Invoke(
this, &GesturePropertiesServiceProviderTest::FakeSetProperty));
service_provider_ = std::make_unique<GesturePropertiesServiceProvider>();
service_provider_->set_service_for_test(mock_service_.get());
}
......@@ -101,6 +105,16 @@ class GesturePropertiesServiceProviderTest : public testing::Test {
std::move(get_property_response_));
}
void FakeSetProperty(
Unused,
Unused,
ui::ozone::mojom::GesturePropValuePtr values,
ui::ozone::mojom::GesturePropertiesService::SetPropertyCallback
callback) {
set_property_values_ = std::move(values);
std::move(callback).Run(set_property_error_code_);
}
protected:
void CallDBusMethod(std::string name,
dbus::MethodCall* method_call,
......@@ -145,6 +159,10 @@ class GesturePropertiesServiceProviderTest : public testing::Test {
bool get_property_read_only_ = true;
ui::ozone::mojom::GesturePropValuePtr get_property_response_ = nullptr;
ui::ozone::mojom::GesturePropValuePtr set_property_values_ = nullptr;
ui::ozone::mojom::SetGesturePropErrorCode set_property_error_code_ =
ui::ozone::mojom::SetGesturePropErrorCode::SUCCESS;
std::unique_ptr<MockGesturePropertiesService> mock_service_;
std::unique_ptr<GesturePropertiesServiceProvider> service_provider_;
......@@ -369,4 +387,139 @@ TEST_F(GesturePropertiesServiceProviderTest, GetPropertyMissingParameters) {
chromeos::kGesturePropertiesServiceGetPropertyMethod);
}
TEST_F(GesturePropertiesServiceProviderTest, SetPropertySuccessInts) {
EXPECT_CALL(*mock_service_, SetProperty(4, "prop 1", _, _));
std::unique_ptr<dbus::Response> response = nullptr;
dbus::MethodCall* method_call = new dbus::MethodCall(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceSetPropertyMethod);
dbus::MessageWriter writer(method_call);
writer.AppendInt32(4);
writer.AppendString("prop 1");
dbus::MessageWriter array_writer(nullptr);
writer.OpenArray("i", &array_writer);
array_writer.AppendInt32(1);
array_writer.AppendInt32(2);
array_writer.AppendInt32(4);
writer.CloseContainer(&array_writer);
CallDBusMethod(chromeos::kGesturePropertiesServiceSetPropertyMethod,
std::move(method_call), response);
EXPECT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
EXPECT_THAT(set_property_values_->get_ints(), ElementsAre(1, 2, 4));
}
TEST_F(GesturePropertiesServiceProviderTest, SetPropertySuccessShorts) {
EXPECT_CALL(*mock_service_, SetProperty(4, "prop 1", _, _));
std::unique_ptr<dbus::Response> response = nullptr;
dbus::MethodCall* method_call = new dbus::MethodCall(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceSetPropertyMethod);
dbus::MessageWriter writer(method_call);
writer.AppendInt32(4);
writer.AppendString("prop 1");
dbus::MessageWriter array_writer(nullptr);
writer.OpenArray("n", &array_writer);
array_writer.AppendInt16(1);
array_writer.AppendInt16(2);
array_writer.AppendInt16(4);
writer.CloseContainer(&array_writer);
CallDBusMethod(chromeos::kGesturePropertiesServiceSetPropertyMethod,
std::move(method_call), response);
EXPECT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
EXPECT_THAT(set_property_values_->get_shorts(), ElementsAre(1, 2, 4));
}
TEST_F(GesturePropertiesServiceProviderTest, SetPropertySuccessBools) {
EXPECT_CALL(*mock_service_, SetProperty(4, "prop 1", _, _));
std::unique_ptr<dbus::Response> response = nullptr;
dbus::MethodCall* method_call = new dbus::MethodCall(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceSetPropertyMethod);
dbus::MessageWriter writer(method_call);
writer.AppendInt32(4);
writer.AppendString("prop 1");
dbus::MessageWriter array_writer(nullptr);
writer.OpenArray("b", &array_writer);
array_writer.AppendBool(true);
array_writer.AppendBool(false);
writer.CloseContainer(&array_writer);
CallDBusMethod(chromeos::kGesturePropertiesServiceSetPropertyMethod,
std::move(method_call), response);
EXPECT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
EXPECT_THAT(set_property_values_->get_bools(), ElementsAre(true, false));
}
TEST_F(GesturePropertiesServiceProviderTest, SetPropertySuccessStr) {
EXPECT_CALL(*mock_service_, SetProperty(4, "prop 1", _, _));
std::unique_ptr<dbus::Response> response = nullptr;
dbus::MethodCall* method_call = new dbus::MethodCall(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceSetPropertyMethod);
dbus::MessageWriter writer(method_call);
writer.AppendInt32(4);
writer.AppendString("prop 1");
writer.AppendString("llamas");
CallDBusMethod(chromeos::kGesturePropertiesServiceSetPropertyMethod,
std::move(method_call), response);
EXPECT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
EXPECT_EQ(set_property_values_->get_str(), "llamas");
}
TEST_F(GesturePropertiesServiceProviderTest, SetPropertySuccessReals) {
EXPECT_CALL(*mock_service_, SetProperty(4, "prop 1", _, _));
std::unique_ptr<dbus::Response> response = nullptr;
dbus::MethodCall* method_call = new dbus::MethodCall(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceSetPropertyMethod);
dbus::MessageWriter writer(method_call);
writer.AppendInt32(4);
writer.AppendString("prop 1");
dbus::MessageWriter array_writer(nullptr);
writer.OpenArray("d", &array_writer);
array_writer.AppendDouble(3.14);
array_writer.AppendDouble(6.28);
writer.CloseContainer(&array_writer);
CallDBusMethod(chromeos::kGesturePropertiesServiceSetPropertyMethod,
std::move(method_call), response);
EXPECT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
EXPECT_THAT(set_property_values_->get_reals(), ElementsAre(3.14, 6.28));
}
TEST_F(GesturePropertiesServiceProviderTest, SetPropertyError) {
set_property_error_code_ =
ui::ozone::mojom::SetGesturePropErrorCode::UNKNOWN_ERROR;
EXPECT_CALL(*mock_service_, SetProperty(4, "prop 1", _, _));
std::unique_ptr<dbus::Response> response = nullptr;
dbus::MethodCall* method_call = new dbus::MethodCall(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceSetPropertyMethod);
dbus::MessageWriter writer(method_call);
writer.AppendInt32(4);
writer.AppendString("prop 1");
writer.AppendString("llamas");
CallDBusMethod(chromeos::kGesturePropertiesServiceSetPropertyMethod,
std::move(method_call), response);
EXPECT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
}
TEST_F(GesturePropertiesServiceProviderTest, SetPropertyNoData) {
std::unique_ptr<dbus::Response> response = nullptr;
dbus::MethodCall* method_call = new dbus::MethodCall(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceSetPropertyMethod);
dbus::MessageWriter writer(method_call);
writer.AppendInt32(4);
writer.AppendString("prop 1");
CallDBusMethod(chromeos::kGesturePropertiesServiceSetPropertyMethod,
std::move(method_call), response);
EXPECT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
}
TEST_F(GesturePropertiesServiceProviderTest, SetPropertyMissingParameters) {
CheckMethodErrorsWithNoParameters(
chromeos::kGesturePropertiesServiceSetPropertyMethod);
}
} // namespace ash
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment