// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/power/auto_screen_brightness/light_samples_observer.h"
#include <utility>
#include "base/functional/bind.h"
#include "chrome/browser/ash/power/auto_screen_brightness/utils.h"
namespace ash {
namespace power {
namespace auto_screen_brightness {
LightSamplesObserver::LightSamplesObserver(
AlsReader* als_reader,
mojo::Remote<chromeos::sensors::mojom::SensorDevice> sensor_device_remote)
: als_reader_(als_reader),
sensor_device_remote_(std::move(sensor_device_remote)) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(sensor_device_remote_.is_bound());
sensor_device_remote_->GetAllChannelIds(
base::BindOnce(&LightSamplesObserver::GetAllChannelIdsCallback,
weak_ptr_factory_.GetWeakPtr()));
}
LightSamplesObserver::~LightSamplesObserver() = default;
void LightSamplesObserver::OnSampleUpdated(
const base::flat_map<int32_t, int64_t>& sample) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(channel_index_.has_value());
DCHECK(als_reader_);
const auto it = sample.find(channel_index_.value());
if (it == sample.end()) {
LogDataError(DataError::kAlsValue);
return;
}
als_reader_->SetLux(it->second);
}
void LightSamplesObserver::OnErrorOccurred(
chromeos::sensors::mojom::ObserverErrorType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (type) {
case chromeos::sensors::mojom::ObserverErrorType::ALREADY_STARTED:
LOG(ERROR) << "Another observer has already started to read samples";
Reset();
break;
case chromeos::sensors::mojom::ObserverErrorType::FREQUENCY_INVALID:
LOG(ERROR) << "Observer started with an invalid frequency";
SetFrequency();
break;
case chromeos::sensors::mojom::ObserverErrorType::NO_ENABLED_CHANNELS:
LOG(ERROR) << "Observer started with no channels enabled";
SetChannelsEnabled();
break;
case chromeos::sensors::mojom::ObserverErrorType::SET_FREQUENCY_IO_FAILED:
LOG(ERROR) << "Failed to set frequency to the physical device";
break;
case chromeos::sensors::mojom::ObserverErrorType::GET_FD_FAILED:
LOG(ERROR) << "Failed to get the device's fd to poll on";
break;
case chromeos::sensors::mojom::ObserverErrorType::READ_FAILED:
LOG(ERROR) << "Failed to read a sample";
break;
case chromeos::sensors::mojom::ObserverErrorType::READ_TIMEOUT:
LOG(ERROR) << "A read timed out";
break;
default:
LOG(ERROR) << "Error: " << static_cast<int>(type);
break;
}
}
void LightSamplesObserver::Reset() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(als_reader_);
LOG(ERROR) << "Resetting LightSamplesObserver";
receiver_.reset();
sensor_device_remote_.reset();
LogDataError(DataError::kMojoSamplesObserver);
}
void LightSamplesObserver::GetAllChannelIdsCallback(
const std::vector<std::string>& iio_channel_ids) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(sensor_device_remote_.is_bound());
for (uint32_t i = 0; i < iio_channel_ids.size(); ++i) {
if (iio_channel_ids[i].compare(chromeos::sensors::mojom::kLightChannel) ==
0) {
channel_index_ = i;
break;
}
}
if (!channel_index_.has_value()) {
LOG(ERROR) << "Missing the available lux channel";
Reset();
return;
}
StartReading();
}
void LightSamplesObserver::StartReading() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(sensor_device_remote_.is_bound());
sensor_device_remote_->SetTimeout(0);
SetFrequency();
SetChannelsEnabled();
sensor_device_remote_->StartReadingSamples(GetPendingRemote());
}
mojo::PendingRemote<chromeos::sensors::mojom::SensorDeviceSamplesObserver>
LightSamplesObserver::GetPendingRemote() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto pending_remote = receiver_.BindNewPipeAndPassRemote();
receiver_.set_disconnect_handler(
base::BindOnce(&LightSamplesObserver::OnObserverDisconnect,
weak_ptr_factory_.GetWeakPtr()));
return pending_remote;
}
void LightSamplesObserver::OnObserverDisconnect() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
LOG(ERROR) << "OnObserverDisconnect";
// Don't reset |sensor_device_remote_| so that LightProviderMojo can get the
// disconnection.
receiver_.reset();
}
void LightSamplesObserver::SetFrequency() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sensor_device_remote_->SetFrequency(
AlsReader::kAlsPollFrequency,
base::BindOnce(&LightSamplesObserver::SetFrequencyCallback,
weak_ptr_factory_.GetWeakPtr()));
}
void LightSamplesObserver::SetFrequencyCallback(double result_frequency) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (result_frequency > 0.0)
return;
LOG(ERROR) << "Failed to set frequency: " << AlsReader::kAlsPollFrequency;
Reset();
}
void LightSamplesObserver::SetChannelsEnabled() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(channel_index_.has_value());
sensor_device_remote_->SetChannelsEnabled(
std::vector<int32_t>{channel_index_.value()},
/*enable=*/true,
base::BindOnce(&LightSamplesObserver::SetChannelsEnabledCallback,
weak_ptr_factory_.GetWeakPtr()));
}
void LightSamplesObserver::SetChannelsEnabledCallback(
const std::vector<int32_t>& failed_indices) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (const int32_t index : failed_indices) {
if (index == channel_index_) {
LOG(ERROR) << "Failed to enable the lux channel: "
<< channel_index_.value();
Reset();
return;
}
LOG(WARNING) << "Failed to enable an unnecessary channel with index: "
<< index;
}
}
} // namespace auto_screen_brightness
} // namespace power
} // namespace ash