Commit cf8e2f1e authored by Harvey Yang's avatar Harvey Yang Committed by Chromium LUCI CQ

accelerometer: Add OnECLidAngleDriverStatusChanged

This commit adds OnECLidAngleDriverStatusChanged in
AccelerometerReader::Observer, which simplifies implementations of
AccelerometerProviderInterface by removing the one-time-read.
This commit also implements AddObserver, RemoveObserver,
StartListenToTabletModeController, and StopListenToTabletModeController
in AccelerometerProviderInterface instead of the derived classes.

BUG=b:171446270, b:172414227
TEST=unit tests and run on kohaku(with iioservice) and helios(without
iioservice)

Change-Id: Ic0d37edc8df22cbd6facf54fe5fb0d11425be2b0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2538855
Commit-Queue: Cheng-Hao Yang <chenghaoyang@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841313}
parent 9481083f
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "base/location.h" #include "base/location.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/numerics/math_constants.h" #include "base/numerics/math_constants.h"
#include "base/observer_list_threadsafe.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
...@@ -142,8 +141,7 @@ bool ReadFileToDouble(const base::FilePath& path, double* value) { ...@@ -142,8 +141,7 @@ bool ReadFileToDouble(const base::FilePath& path, double* value) {
} // namespace } // namespace
AccelerometerFileReader::AccelerometerFileReader() AccelerometerFileReader::AccelerometerFileReader() = default;
: ui_task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
void AccelerometerFileReader::PrepareAndInitialize() { void AccelerometerFileReader::PrepareAndInitialize() {
DCHECK(base::CurrentUIThread::IsSet()); DCHECK(base::CurrentUIThread::IsSet());
...@@ -165,62 +163,11 @@ void AccelerometerFileReader::PrepareAndInitialize() { ...@@ -165,62 +163,11 @@ void AccelerometerFileReader::PrepareAndInitialize() {
TryScheduleInitialize(); TryScheduleInitialize();
} }
void AccelerometerFileReader::AddObserver(
AccelerometerReader::Observer* observer) {
DCHECK(base::CurrentUIThread::IsSet());
DCHECK(blocking_task_runner_);
observers_.AddObserver(observer);
if (initialization_state_ != State::SUCCESS)
return;
blocking_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&AccelerometerFileReader::ReadSample, this));
}
void AccelerometerFileReader::RemoveObserver(
AccelerometerReader::Observer* observer) {
DCHECK(base::CurrentUIThread::IsSet());
observers_.RemoveObserver(observer);
}
void AccelerometerFileReader::StartListenToTabletModeController() {
DCHECK(base::CurrentUIThread::IsSet());
Shell::Get()->tablet_mode_controller()->AddObserver(this);
}
void AccelerometerFileReader::StopListenToTabletModeController() {
DCHECK(base::CurrentUIThread::IsSet());
Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
}
void AccelerometerFileReader::SetEmitEvents(bool emit_events) {
DCHECK(base::CurrentUIThread::IsSet());
emit_events_ = emit_events;
}
void AccelerometerFileReader::EnableAccelerometerReading() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (read_refresh_timer_.IsRunning())
return;
read_refresh_timer_.Start(FROM_HERE, kDelayBetweenReads, this,
&AccelerometerFileReader::ReadSample);
}
void AccelerometerFileReader::DisableAccelerometerReading() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!read_refresh_timer_.IsRunning())
return;
read_refresh_timer_.Stop();
}
void AccelerometerFileReader::TriggerRead() { void AccelerometerFileReader::TriggerRead() {
DCHECK(base::CurrentUIThread::IsSet()); DCHECK(base::CurrentUIThread::IsSet());
switch (initialization_state_) { switch (initialization_state_) {
case State::SUCCESS: case State::SUCCESS:
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::SUPPORTED) { if (GetECLidAngleDriverStatus() == ECLidAngleDriverStatus::SUPPORTED) {
blocking_task_runner_->PostTask( blocking_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&AccelerometerFileReader::EnableAccelerometerReading, base::BindOnce(&AccelerometerFileReader::EnableAccelerometerReading,
...@@ -242,7 +189,7 @@ void AccelerometerFileReader::TriggerRead() { ...@@ -242,7 +189,7 @@ void AccelerometerFileReader::TriggerRead() {
void AccelerometerFileReader::CancelRead() { void AccelerometerFileReader::CancelRead() {
DCHECK(base::CurrentUIThread::IsSet()); DCHECK(base::CurrentUIThread::IsSet());
if (initialization_state_ == State::SUCCESS && if (initialization_state_ == State::SUCCESS &&
ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::SUPPORTED) { GetECLidAngleDriverStatus() == ECLidAngleDriverStatus::SUPPORTED) {
blocking_task_runner_->PostTask( blocking_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&AccelerometerFileReader::DisableAccelerometerReading, base::BindOnce(&AccelerometerFileReader::DisableAccelerometerReading,
...@@ -250,30 +197,6 @@ void AccelerometerFileReader::CancelRead() { ...@@ -250,30 +197,6 @@ void AccelerometerFileReader::CancelRead() {
} }
} }
void AccelerometerFileReader::OnTabletPhysicalStateChanged() {
DCHECK(base::CurrentUIThread::IsSet());
// When CrOS EC lid angle driver is not present, accelerometer read is always
// ON and can't be tuned. Thus AccelerometerFileReader no longer listens to
// tablet mode event.
auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller();
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::NOT_SUPPORTED) {
tablet_mode_controller->RemoveObserver(this);
return;
}
// Auto rotation is turned on when the device is physically used as a tablet
// (i.e. flipped or detached), regardless of the UI state (i.e. whether tablet
// mode is turned on or off).
const bool is_auto_rotation_on =
tablet_mode_controller->is_in_tablet_physical_state();
if (is_auto_rotation_on)
TriggerRead();
else
CancelRead();
}
AccelerometerFileReader::InitializationResult::InitializationResult() AccelerometerFileReader::InitializationResult::InitializationResult()
: initialization_state(State::INITIALIZING), : initialization_state(State::INITIALIZING),
ec_lid_angle_driver_status(ECLidAngleDriverStatus::UNKNOWN) {} ec_lid_angle_driver_status(ECLidAngleDriverStatus::UNKNOWN) {}
...@@ -465,9 +388,9 @@ void AccelerometerFileReader::SetStatesWithInitializationResult( ...@@ -465,9 +388,9 @@ void AccelerometerFileReader::SetStatesWithInitializationResult(
case State::SUCCESS: case State::SUCCESS:
DCHECK_NE(result.ec_lid_angle_driver_status, DCHECK_NE(result.ec_lid_angle_driver_status,
ECLidAngleDriverStatus::UNKNOWN); ECLidAngleDriverStatus::UNKNOWN);
ec_lid_angle_driver_status_ = result.ec_lid_angle_driver_status; SetECLidAngleDriverStatus(result.ec_lid_angle_driver_status);
if (ec_lid_angle_driver_status_ == if (GetECLidAngleDriverStatus() ==
ECLidAngleDriverStatus::NOT_SUPPORTED) { ECLidAngleDriverStatus::NOT_SUPPORTED) {
// If ChromeOS lid angle driver is not present, start accelerometer read // If ChromeOS lid angle driver is not present, start accelerometer read
// and read is always on. // and read is always on.
...@@ -593,6 +516,20 @@ bool AccelerometerFileReader::InitializeLegacyAccelerometers( ...@@ -593,6 +516,20 @@ bool AccelerometerFileReader::InitializeLegacyAccelerometers(
return true; return true;
} }
void AccelerometerFileReader::EnableAccelerometerReading() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (read_refresh_timer_.IsRunning())
return;
read_refresh_timer_.Start(FROM_HERE, kDelayBetweenReads, this,
&AccelerometerFileReader::ReadSample);
}
void AccelerometerFileReader::DisableAccelerometerReading() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
read_refresh_timer_.Stop();
}
void AccelerometerFileReader::ReadSample() { void AccelerometerFileReader::ReadSample() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
...@@ -640,19 +577,8 @@ void AccelerometerFileReader::ReadSample() { ...@@ -640,19 +577,8 @@ void AccelerometerFileReader::ReadSample() {
ui_task_runner_->PostTask( ui_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&AccelerometerFileReader::NotifyObserversWithUpdate, this, base::BindOnce(&AccelerometerFileReader::NotifyAccelerometerUpdated, this,
update)); update));
} }
void AccelerometerFileReader::NotifyObserversWithUpdate(
const AccelerometerUpdate& update) {
DCHECK(base::CurrentUIThread::IsSet());
if (!emit_events_)
return;
for (auto& observer : observers_)
observer.OnAccelerometerUpdated(update);
}
} // namespace ash } // namespace ash
...@@ -9,9 +9,7 @@ ...@@ -9,9 +9,7 @@
#include <vector> #include <vector>
#include "ash/accelerometer/accelerometer_reader.h" #include "ash/accelerometer/accelerometer_reader.h"
#include "ash/public/cpp/tablet_mode_observer.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
...@@ -20,8 +18,7 @@ namespace ash { ...@@ -20,8 +18,7 @@ namespace ash {
// Work that runs on a base::TaskRunner. It determines the accelerometer // Work that runs on a base::TaskRunner. It determines the accelerometer
// configuration, and reads the data. Upon a successful read it will notify // configuration, and reads the data. Upon a successful read it will notify
// all observers. // all observers.
class AccelerometerFileReader : public AccelerometerProviderInterface, class AccelerometerFileReader : public AccelerometerProviderInterface {
public TabletModeObserver {
public: public:
AccelerometerFileReader(); AccelerometerFileReader();
AccelerometerFileReader(const AccelerometerFileReader&) = delete; AccelerometerFileReader(const AccelerometerFileReader&) = delete;
...@@ -29,24 +26,8 @@ class AccelerometerFileReader : public AccelerometerProviderInterface, ...@@ -29,24 +26,8 @@ class AccelerometerFileReader : public AccelerometerProviderInterface,
// AccelerometerProviderInterface: // AccelerometerProviderInterface:
void PrepareAndInitialize() override; void PrepareAndInitialize() override;
void AddObserver(AccelerometerReader::Observer* observer) override; void TriggerRead() override;
void RemoveObserver(AccelerometerReader::Observer* observer) override; void CancelRead() override;
void StartListenToTabletModeController() override;
void StopListenToTabletModeController() override;
void SetEmitEvents(bool emit_events) override;
// Controls accelerometer reading.
void EnableAccelerometerReading();
void DisableAccelerometerReading();
// With ChromeOS EC lid angle driver present, it's triggered when the device
// is physically used as a tablet (even thought its UI might be in clamshell
// mode), cancelled otherwise.
void TriggerRead();
void CancelRead();
// TabletModeObserver:
void OnTabletPhysicalStateChanged() override;
private: private:
struct InitializationResult { struct InitializationResult {
...@@ -97,11 +78,11 @@ class AccelerometerFileReader : public AccelerometerProviderInterface, ...@@ -97,11 +78,11 @@ class AccelerometerFileReader : public AccelerometerProviderInterface,
~AccelerometerFileReader() override; ~AccelerometerFileReader() override;
// Post a task to initialize on |task_runner_| and process the result on the // Post a task to initialize on |blocking_task_runner_| and process the result
// UI thread. May be called multiple times in the retries. // on the UI thread. May be called multiple times in the retries.
void TryScheduleInitialize(); void TryScheduleInitialize();
// Detects the accelerometer configuration in |task_runner_|. // Detects the accelerometer configuration in |blocking_task_runner_|.
// If an accelerometer is available, it triggers reads. // If an accelerometer is available, it triggers reads.
// This function MAY be called more than once. // This function MAY be called more than once.
// This function contains the actual initialization code to be run by the // This function contains the actual initialization code to be run by the
...@@ -130,12 +111,14 @@ class AccelerometerFileReader : public AccelerometerProviderInterface, ...@@ -130,12 +111,14 @@ class AccelerometerFileReader : public AccelerometerProviderInterface,
bool InitializeLegacyAccelerometers(const base::FilePath& iio_path, bool InitializeLegacyAccelerometers(const base::FilePath& iio_path,
const base::FilePath& name); const base::FilePath& name);
// Attempts to read the accelerometer data in |task_runner_|. Upon a success, // Controls accelerometer reading.
// converts the raw reading to an AccelerometerUpdate and notifies observers. void EnableAccelerometerReading();
void ReadSample(); void DisableAccelerometerReading();
void NotifyObserversWithUpdate(const AccelerometerUpdate& update);
bool emit_events_ = true; // Attempts to read the accelerometer data in |blocking_task_runner_|. Upon a
// success, converts the raw reading to an AccelerometerUpdate and notifies
// observers.
void ReadSample();
// The time at which initialization re-tries should stop. // The time at which initialization re-tries should stop.
base::TimeTicks initialization_timeout_; base::TimeTicks initialization_timeout_;
...@@ -149,15 +132,9 @@ class AccelerometerFileReader : public AccelerometerProviderInterface, ...@@ -149,15 +132,9 @@ class AccelerometerFileReader : public AccelerometerProviderInterface,
base::RepeatingTimer read_refresh_timer_ base::RepeatingTimer read_refresh_timer_
GUARDED_BY_CONTEXT(sequence_checker_); GUARDED_BY_CONTEXT(sequence_checker_);
// The observers to notify of accelerometer updates.
base::ObserverList<AccelerometerReader::Observer>::Unchecked observers_;
// The task runner to use for blocking tasks. // The task runner to use for blocking tasks.
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
// The task runner of the UI thread.
scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
}; };
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/observer_list_threadsafe.h"
#include "base/ranges/algorithm.h" #include "base/ranges/algorithm.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
...@@ -33,89 +32,20 @@ AccelerometerProviderMojo::AccelerometerProviderMojo() = default; ...@@ -33,89 +32,20 @@ AccelerometerProviderMojo::AccelerometerProviderMojo() = default;
void AccelerometerProviderMojo::PrepareAndInitialize() { void AccelerometerProviderMojo::PrepareAndInitialize() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This function should only be called once.
DCHECK(!task_runner_);
task_runner_ = base::SequencedTaskRunnerHandle::Get(); RegisterSensorClient();
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&AccelerometerProviderMojo::RegisterSensorClient,
base::Unretained(this)));
}
void AccelerometerProviderMojo::AddObserver(
AccelerometerReader::Observer* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(task_runner_);
observers_.AddObserver(observer);
one_time_read_ = true;
if (accelerometer_read_on_)
return;
for (auto& accelerometer : accelerometers_) {
if (!accelerometer.second.samples_observer.get())
continue;
accelerometer.second.samples_observer->SetEnabled(true);
}
} }
void AccelerometerProviderMojo::RemoveObserver( void AccelerometerProviderMojo::TriggerRead() {
AccelerometerReader::Observer* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(task_runner_);
observers_.RemoveObserver(observer);
}
void AccelerometerProviderMojo::StartListenToTabletModeController() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Shell::Get()->tablet_mode_controller()->AddObserver(this);
}
void AccelerometerProviderMojo::StopListenToTabletModeController() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
}
void AccelerometerProviderMojo::SetEmitEvents(bool emit_events) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
emit_events_ = emit_events; if (GetECLidAngleDriverStatus() == ECLidAngleDriverStatus::SUPPORTED)
EnableAccelerometerReading();
} }
void AccelerometerProviderMojo::OnTabletPhysicalStateChanged() { void AccelerometerProviderMojo::CancelRead() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (GetECLidAngleDriverStatus() == ECLidAngleDriverStatus::SUPPORTED)
// Wait until the existence of the driver is determined. DisableAccelerometerReading();
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::UNKNOWN) {
pending_on_tablet_physical_state_changed_ = true;
return;
}
// When CrOS EC lid angle driver is not present, accelerometer read is always
// ON and can't be tuned. Thus AccelerometerProviderMojo no longer listens
// to tablet mode event.
auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller();
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::NOT_SUPPORTED) {
tablet_mode_controller->RemoveObserver(this);
return;
}
// Auto rotation is turned on when the device is physically used as a tablet
// (i.e. flipped or detached), regardless of the UI state (i.e. whether tablet
// mode is turned on or off).
const bool is_auto_rotation_on =
tablet_mode_controller->is_in_tablet_physical_state();
task_runner_->PostNonNestableTask(
FROM_HERE,
is_auto_rotation_on
? base::BindOnce(&AccelerometerProviderMojo::TriggerRead, this)
: base::BindOnce(&AccelerometerProviderMojo::CancelRead, this));
} }
void AccelerometerProviderMojo::SetUpChannel( void AccelerometerProviderMojo::SetUpChannel(
...@@ -127,37 +57,33 @@ void AccelerometerProviderMojo::SetUpChannel( ...@@ -127,37 +57,33 @@ void AccelerometerProviderMojo::SetUpChannel(
return; return;
} }
sensor_service_remote_.Bind(std::move(pending_remote), task_runner_); sensor_service_remote_.Bind(std::move(pending_remote));
sensor_service_remote_.set_disconnect_handler( sensor_service_remote_.set_disconnect_handler(base::BindOnce(
base::BindOnce(&AccelerometerProviderMojo::OnSensorServiceDisconnect, &AccelerometerProviderMojo::OnSensorServiceDisconnect, this));
base::Unretained(this))); if (GetECLidAngleDriverStatus() == ECLidAngleDriverStatus::UNKNOWN) {
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::UNKNOWN) {
sensor_service_remote_->GetDeviceIds( sensor_service_remote_->GetDeviceIds(
chromeos::sensors::mojom::DeviceType::ANGL, chromeos::sensors::mojom::DeviceType::ANGL,
base::BindOnce(&AccelerometerProviderMojo::GetLidAngleIdsCallback, base::BindOnce(&AccelerometerProviderMojo::GetLidAngleIdsCallback,
base::Unretained(this))); this));
} }
sensor_service_remote_->GetDeviceIds( sensor_service_remote_->GetDeviceIds(
chromeos::sensors::mojom::DeviceType::ACCEL, chromeos::sensors::mojom::DeviceType::ACCEL,
base::BindOnce(&AccelerometerProviderMojo::GetAccelerometerIdsCallback, base::BindOnce(&AccelerometerProviderMojo::GetAccelerometerIdsCallback,
base::Unretained(this))); this));
} }
void AccelerometerProviderMojo::TriggerRead() { State AccelerometerProviderMojo::GetInitializationStateForTesting() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return initialization_state_;
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::SUPPORTED)
EnableAccelerometerReading();
} }
void AccelerometerProviderMojo::CancelRead() { bool AccelerometerProviderMojo::ShouldDelayOnTabletPhysicalStateChanged() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (GetECLidAngleDriverStatus() == ECLidAngleDriverStatus::UNKNOWN) {
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::SUPPORTED) pending_on_tablet_physical_state_changed_ = true;
DisableAccelerometerReading(); return true;
} }
State AccelerometerProviderMojo::GetInitializationStateForTesting() const { return false;
return initialization_state_;
} }
AccelerometerProviderMojo::AccelerometerData::AccelerometerData() = default; AccelerometerProviderMojo::AccelerometerData::AccelerometerData() = default;
...@@ -171,9 +97,8 @@ void AccelerometerProviderMojo::RegisterSensorClient() { ...@@ -171,9 +97,8 @@ void AccelerometerProviderMojo::RegisterSensorClient() {
chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterClient( chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterClient(
sensor_hal_client_.BindNewPipeAndPassRemote()); sensor_hal_client_.BindNewPipeAndPassRemote());
sensor_hal_client_.set_disconnect_handler( sensor_hal_client_.set_disconnect_handler(base::BindOnce(
base::BindOnce(&AccelerometerProviderMojo::OnSensorHalClientFailure, &AccelerometerProviderMojo::OnSensorHalClientFailure, this));
base::Unretained(this)));
} }
void AccelerometerProviderMojo::OnSensorHalClientFailure() { void AccelerometerProviderMojo::OnSensorHalClientFailure() {
...@@ -184,10 +109,9 @@ void AccelerometerProviderMojo::OnSensorHalClientFailure() { ...@@ -184,10 +109,9 @@ void AccelerometerProviderMojo::OnSensorHalClientFailure() {
ResetSensorService(); ResetSensorService();
sensor_hal_client_.reset(); sensor_hal_client_.reset();
task_runner_->PostDelayedTask( ui_task_runner_->PostDelayedTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&AccelerometerProviderMojo::RegisterSensorClient, base::BindOnce(&AccelerometerProviderMojo::RegisterSensorClient, this),
base::Unretained(this)),
kDelayReconnect); kDelayReconnect);
} }
...@@ -212,12 +136,12 @@ void AccelerometerProviderMojo::ResetSensorService() { ...@@ -212,12 +136,12 @@ void AccelerometerProviderMojo::ResetSensorService() {
void AccelerometerProviderMojo::GetLidAngleIdsCallback( void AccelerometerProviderMojo::GetLidAngleIdsCallback(
const std::vector<int32_t>& lid_angle_ids) { const std::vector<int32_t>& lid_angle_ids) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(ec_lid_angle_driver_status_, ECLidAngleDriverStatus::UNKNOWN); DCHECK_EQ(GetECLidAngleDriverStatus(), ECLidAngleDriverStatus::UNKNOWN);
if (!lid_angle_ids.empty()) { if (!lid_angle_ids.empty()) {
ec_lid_angle_driver_status_ = ECLidAngleDriverStatus::SUPPORTED; SetECLidAngleDriverStatus(ECLidAngleDriverStatus::SUPPORTED);
} else { } else {
ec_lid_angle_driver_status_ = ECLidAngleDriverStatus::NOT_SUPPORTED; SetECLidAngleDriverStatus(ECLidAngleDriverStatus::NOT_SUPPORTED);
EnableAccelerometerReading(); EnableAccelerometerReading();
} }
...@@ -261,8 +185,7 @@ void AccelerometerProviderMojo::RegisterAccelerometerWithId(int32_t id) { ...@@ -261,8 +185,7 @@ void AccelerometerProviderMojo::RegisterAccelerometerWithId(int32_t id) {
sensor_service_remote_->GetDevice( sensor_service_remote_->GetDevice(
id, accelerometer.remote.BindNewPipeAndPassReceiver()); id, accelerometer.remote.BindNewPipeAndPassReceiver());
accelerometer.remote.set_disconnect_handler(base::BindOnce( accelerometer.remote.set_disconnect_handler(base::BindOnce(
&AccelerometerProviderMojo::OnAccelerometerRemoteDisconnect, &AccelerometerProviderMojo::OnAccelerometerRemoteDisconnect, this, id));
base::Unretained(this), id));
std::vector<std::string> attr_names; std::vector<std::string> attr_names;
if (!accelerometer.location.has_value()) if (!accelerometer.location.has_value())
...@@ -273,8 +196,8 @@ void AccelerometerProviderMojo::RegisterAccelerometerWithId(int32_t id) { ...@@ -273,8 +196,8 @@ void AccelerometerProviderMojo::RegisterAccelerometerWithId(int32_t id) {
if (!attr_names.empty()) { if (!attr_names.empty()) {
accelerometer.remote->GetAttributes( accelerometer.remote->GetAttributes(
attr_names, attr_names,
base::BindOnce(&AccelerometerProviderMojo::GetAttributesCallback, base::BindOnce(&AccelerometerProviderMojo::GetAttributesCallback, this,
base::Unretained(this), id)); id));
} else { } else {
// Create the observer directly if the attributes have already been // Create the observer directly if the attributes have already been
// retrieved. // retrieved.
...@@ -378,7 +301,7 @@ void AccelerometerProviderMojo::IgnoreAccelerometer(int32_t id) { ...@@ -378,7 +301,7 @@ void AccelerometerProviderMojo::IgnoreAccelerometer(int32_t id) {
void AccelerometerProviderMojo::CheckInitialization() { void AccelerometerProviderMojo::CheckInitialization() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(ec_lid_angle_driver_status_, ECLidAngleDriverStatus::UNKNOWN); DCHECK_NE(GetECLidAngleDriverStatus(), ECLidAngleDriverStatus::UNKNOWN);
if (initialization_state_ != State::INITIALIZING) if (initialization_state_ != State::INITIALIZING)
return; return;
...@@ -390,7 +313,7 @@ void AccelerometerProviderMojo::CheckInitialization() { ...@@ -390,7 +313,7 @@ void AccelerometerProviderMojo::CheckInitialization() {
continue; continue;
if (accelerometer.second.location == ACCELEROMETER_SOURCE_SCREEN || if (accelerometer.second.location == ACCELEROMETER_SOURCE_SCREEN ||
ec_lid_angle_driver_status_ == GetECLidAngleDriverStatus() ==
ECLidAngleDriverStatus::NOT_SUPPORTED) { ECLidAngleDriverStatus::NOT_SUPPORTED) {
// This ignored accelerometer is essential. // This ignored accelerometer is essential.
FailedToInitialize(); FailedToInitialize();
...@@ -431,7 +354,7 @@ void AccelerometerProviderMojo::CreateAccelerometerSamplesObserver(int32_t id) { ...@@ -431,7 +354,7 @@ void AccelerometerProviderMojo::CreateAccelerometerSamplesObserver(int32_t id) {
DCHECK(accelerometer.scale.has_value() && accelerometer.location.has_value()); DCHECK(accelerometer.scale.has_value() && accelerometer.location.has_value());
if (accelerometer.location == ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD && if (accelerometer.location == ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD &&
ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::SUPPORTED) { GetECLidAngleDriverStatus() == ECLidAngleDriverStatus::SUPPORTED) {
// Skipping as it's only needed if lid-angle is not supported. // Skipping as it's only needed if lid-angle is not supported.
// |GetLidAngleIdsCallback| will call this function with this |id| again if // |GetLidAngleIdsCallback| will call this function with this |id| again if
// it's found not supported. // it's found not supported.
...@@ -442,16 +365,15 @@ void AccelerometerProviderMojo::CreateAccelerometerSamplesObserver(int32_t id) { ...@@ -442,16 +365,15 @@ void AccelerometerProviderMojo::CreateAccelerometerSamplesObserver(int32_t id) {
std::make_unique<AccelerometerSamplesObserver>( std::make_unique<AccelerometerSamplesObserver>(
id, std::move(accelerometer.remote), accelerometer.scale.value(), id, std::move(accelerometer.remote), accelerometer.scale.value(),
base::BindRepeating( base::BindRepeating(
&AccelerometerProviderMojo::OnSampleUpdatedCallback, &AccelerometerProviderMojo::OnSampleUpdatedCallback, this));
base::Unretained(this)));
if (accelerometer_read_on_ || one_time_read_) if (accelerometer_read_on_)
accelerometer.samples_observer->SetEnabled(true); accelerometer.samples_observer->SetEnabled(true);
} }
void AccelerometerProviderMojo::EnableAccelerometerReading() { void AccelerometerProviderMojo::EnableAccelerometerReading() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(ec_lid_angle_driver_status_, ECLidAngleDriverStatus::UNKNOWN); DCHECK_NE(GetECLidAngleDriverStatus(), ECLidAngleDriverStatus::UNKNOWN);
if (accelerometer_read_on_) if (accelerometer_read_on_)
return; return;
...@@ -466,17 +388,12 @@ void AccelerometerProviderMojo::EnableAccelerometerReading() { ...@@ -466,17 +388,12 @@ void AccelerometerProviderMojo::EnableAccelerometerReading() {
void AccelerometerProviderMojo::DisableAccelerometerReading() { void AccelerometerProviderMojo::DisableAccelerometerReading() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(ec_lid_angle_driver_status_, ECLidAngleDriverStatus::SUPPORTED); DCHECK_EQ(GetECLidAngleDriverStatus(), ECLidAngleDriverStatus::SUPPORTED);
if (!accelerometer_read_on_) if (!accelerometer_read_on_)
return; return;
accelerometer_read_on_ = false; accelerometer_read_on_ = false;
// Allow one more read and let |OnSampleUpdatedCallback| disable the
// observers.
if (one_time_read_)
return;
for (auto& accelerometer : accelerometers_) { for (auto& accelerometer : accelerometers_) {
if (!accelerometer.second.samples_observer.get()) if (!accelerometer.second.samples_observer.get())
continue; continue;
...@@ -495,17 +412,14 @@ void AccelerometerProviderMojo::OnSampleUpdatedCallback( ...@@ -495,17 +412,14 @@ void AccelerometerProviderMojo::OnSampleUpdatedCallback(
DCHECK(accelerometer.location.has_value()); DCHECK(accelerometer.location.has_value());
bool need_two_accelerometers = bool need_two_accelerometers =
(ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::NOT_SUPPORTED && (GetECLidAngleDriverStatus() == ECLidAngleDriverStatus::NOT_SUPPORTED &&
has_accelerometer_base_); has_accelerometer_base_);
if (!one_time_read_ && !accelerometer_read_on_) { if (!accelerometer_read_on_) {
// This sample is not needed. // This sample is not needed.
return; return;
} }
if (!emit_events_)
return;
update_.Set(accelerometers_[iio_device_id].location.value(), sample[0], update_.Set(accelerometers_[iio_device_id].location.value(), sample[0],
sample[1], sample[2]); sample[1], sample[2]);
...@@ -516,22 +430,8 @@ void AccelerometerProviderMojo::OnSampleUpdatedCallback( ...@@ -516,22 +430,8 @@ void AccelerometerProviderMojo::OnSampleUpdatedCallback(
return; return;
} }
for (auto& observer : observers_) NotifyAccelerometerUpdated(update_);
observer.OnAccelerometerUpdated(update_);
update_.Reset(); update_.Reset();
one_time_read_ = false;
if (accelerometer_read_on_)
return;
// This was a one time read. Disable observers.
for (auto& accelerometer : accelerometers_) {
if (!accelerometer.second.samples_observer.get())
continue;
accelerometer.second.samples_observer->SetEnabled(false);
}
} }
void AccelerometerProviderMojo::FailedToInitialize() { void AccelerometerProviderMojo::FailedToInitialize() {
......
...@@ -15,11 +15,8 @@ ...@@ -15,11 +15,8 @@
#include "ash/accelerometer/accelerometer_reader.h" #include "ash/accelerometer/accelerometer_reader.h"
#include "ash/accelerometer/accelerometer_samples_observer.h" #include "ash/accelerometer/accelerometer_samples_observer.h"
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/public/cpp/tablet_mode_observer.h"
#include "base/observer_list.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/remote.h"
...@@ -31,7 +28,6 @@ namespace ash { ...@@ -31,7 +28,6 @@ namespace ash {
// observers. // observers.
class ASH_EXPORT AccelerometerProviderMojo class ASH_EXPORT AccelerometerProviderMojo
: public AccelerometerProviderInterface, : public AccelerometerProviderInterface,
public TabletModeObserver,
public chromeos::sensors::mojom::SensorHalClient { public chromeos::sensors::mojom::SensorHalClient {
public: public:
AccelerometerProviderMojo(); AccelerometerProviderMojo();
...@@ -41,27 +37,19 @@ class ASH_EXPORT AccelerometerProviderMojo ...@@ -41,27 +37,19 @@ class ASH_EXPORT AccelerometerProviderMojo
// AccelerometerProviderInterface: // AccelerometerProviderInterface:
void PrepareAndInitialize() override; void PrepareAndInitialize() override;
void AddObserver(AccelerometerReader::Observer* observer) override; void TriggerRead() override;
void RemoveObserver(AccelerometerReader::Observer* observer) override; void CancelRead() override;
void StartListenToTabletModeController() override;
void StopListenToTabletModeController() override;
void SetEmitEvents(bool emit_events) override;
// TabletModeObserver:
void OnTabletPhysicalStateChanged() override;
// chromeos::sensors::mojom::SensorHalClient: // chromeos::sensors::mojom::SensorHalClient:
void SetUpChannel(mojo::PendingRemote<chromeos::sensors::mojom::SensorService> void SetUpChannel(mojo::PendingRemote<chromeos::sensors::mojom::SensorService>
pending_remote) override; pending_remote) override;
// With ChromeOS EC lid angle driver present, it's triggered when the device
// is physically used as a tablet (even thought its UI might be in clamshell
// mode), cancelled otherwise.
void TriggerRead();
void CancelRead();
State GetInitializationStateForTesting() const; State GetInitializationStateForTesting() const;
protected:
// AccelerometerProviderInterface:
bool ShouldDelayOnTabletPhysicalStateChanged() override;
private: private:
struct AccelerometerData { struct AccelerometerData {
AccelerometerData(); AccelerometerData();
...@@ -117,15 +105,13 @@ class ASH_EXPORT AccelerometerProviderMojo ...@@ -117,15 +105,13 @@ class ASH_EXPORT AccelerometerProviderMojo
void EnableAccelerometerReading(); void EnableAccelerometerReading();
void DisableAccelerometerReading(); void DisableAccelerometerReading();
// Called by |observers_|, containing a sample of the accelerometer. // Called by |AccelerometerData::samples_observer| stored in the
// |accelerometers_| map, containing a sample of the accelerometer.
void OnSampleUpdatedCallback(int iio_device_id, std::vector<float> sample); void OnSampleUpdatedCallback(int iio_device_id, std::vector<float> sample);
// Sets FAILED to |initialization_state_| due to an error. // Sets FAILED to |initialization_state_| due to an error.
void FailedToInitialize(); void FailedToInitialize();
// The task runner to use for blocking tasks.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// The Mojo channel connecting to Sensor Hal Dispatcher. // The Mojo channel connecting to Sensor Hal Dispatcher.
mojo::Receiver<chromeos::sensors::mojom::SensorHalClient> sensor_hal_client_{ mojo::Receiver<chromeos::sensors::mojom::SensorHalClient> sensor_hal_client_{
this}; this};
...@@ -148,20 +134,9 @@ class ASH_EXPORT AccelerometerProviderMojo ...@@ -148,20 +134,9 @@ class ASH_EXPORT AccelerometerProviderMojo
// |ec_lid_angle_driver_status_| is set. // |ec_lid_angle_driver_status_| is set.
bool pending_on_tablet_physical_state_changed_ = false; bool pending_on_tablet_physical_state_changed_ = false;
// One time read upon |AddObserver|.
// Some observers need to know ECLidAngleDriverStatus, and it's guaranteed to
// be set before reading samples. When adding an observer, trigger at least
// one sample to notify observers that ECLidAngleDriverStatus has been set.
bool one_time_read_ = false;
// True if periodical accelerometer read is on. // True if periodical accelerometer read is on.
bool accelerometer_read_on_ = false; bool accelerometer_read_on_ = false;
bool emit_events_ = true;
// The observers to notify of accelerometer updates.
base::ObserverList<AccelerometerReader::Observer>::Unchecked observers_;
// The last seen accelerometer data. // The last seen accelerometer data.
AccelerometerUpdate update_; AccelerometerUpdate update_;
......
...@@ -32,6 +32,10 @@ constexpr int64_t kFakeSampleData[] = {1, 2, 3}; ...@@ -32,6 +32,10 @@ constexpr int64_t kFakeSampleData[] = {1, 2, 3};
class FakeObserver : public AccelerometerReader::Observer { class FakeObserver : public AccelerometerReader::Observer {
public: public:
void OnECLidAngleDriverStatusChanged(bool is_supported) override {
CHECK(!is_supported_.has_value());
is_supported_ = is_supported;
}
void OnAccelerometerUpdated(const AccelerometerUpdate& update) override { void OnAccelerometerUpdated(const AccelerometerUpdate& update) override {
for (uint32_t index = 0; index < ACCELEROMETER_SOURCE_COUNT; ++index) { for (uint32_t index = 0; index < ACCELEROMETER_SOURCE_COUNT; ++index) {
auto source = static_cast<AccelerometerSource>(index); auto source = static_cast<AccelerometerSource>(index);
...@@ -46,6 +50,7 @@ class FakeObserver : public AccelerometerReader::Observer { ...@@ -46,6 +50,7 @@ class FakeObserver : public AccelerometerReader::Observer {
update_ = update; update_ = update;
} }
base::Optional<bool> is_supported_;
AccelerometerUpdate update_; AccelerometerUpdate update_;
}; };
...@@ -103,7 +108,8 @@ class AccelerometerProviderMojoTest : public ::testing::Test { ...@@ -103,7 +108,8 @@ class AccelerometerProviderMojoTest : public ::testing::Test {
std::unique_ptr<chromeos::sensors::FakeSensorHalServer> sensor_hal_server_; std::unique_ptr<chromeos::sensors::FakeSensorHalServer> sensor_hal_server_;
scoped_refptr<AccelerometerProviderMojo> provider_; scoped_refptr<AccelerometerProviderMojo> provider_;
base::test::SingleThreadTaskEnvironment task_environment; base::test::SingleThreadTaskEnvironment task_environment{
base::test::TaskEnvironment::MainThreadType::UI};
}; };
TEST_F(AccelerometerProviderMojoTest, CheckNoScale) { TEST_F(AccelerometerProviderMojoTest, CheckNoScale) {
...@@ -117,6 +123,8 @@ TEST_F(AccelerometerProviderMojoTest, CheckNoScale) { ...@@ -117,6 +123,8 @@ TEST_F(AccelerometerProviderMojoTest, CheckNoScale) {
// Wait until initialization failed. // Wait until initialization failed.
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_TRUE(observer_.is_supported_.has_value());
EXPECT_FALSE(observer_.is_supported_.value());
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::FAILED); EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::FAILED);
} }
...@@ -131,6 +139,8 @@ TEST_F(AccelerometerProviderMojoTest, CheckNoLocation) { ...@@ -131,6 +139,8 @@ TEST_F(AccelerometerProviderMojoTest, CheckNoLocation) {
// Wait until initialization failed. // Wait until initialization failed.
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_TRUE(observer_.is_supported_.has_value());
EXPECT_FALSE(observer_.is_supported_.value());
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS); EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS);
} }
...@@ -141,6 +151,8 @@ TEST_F(AccelerometerProviderMojoTest, GetSamplesOfOneAccel) { ...@@ -141,6 +151,8 @@ TEST_F(AccelerometerProviderMojoTest, GetSamplesOfOneAccel) {
// Wait until a sample is received. // Wait until a sample is received.
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_TRUE(observer_.is_supported_.has_value());
EXPECT_FALSE(observer_.is_supported_.value());
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS); EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS);
EXPECT_TRUE(observer_.update_.has(ACCELEROMETER_SOURCE_SCREEN)); EXPECT_TRUE(observer_.update_.has(ACCELEROMETER_SOURCE_SCREEN));
...@@ -159,6 +171,8 @@ TEST_F(AccelerometerProviderMojoTest, GetSamplesWithNoLidAngle) { ...@@ -159,6 +171,8 @@ TEST_F(AccelerometerProviderMojoTest, GetSamplesWithNoLidAngle) {
// Wait until samples are received. // Wait until samples are received.
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_TRUE(observer_.is_supported_.has_value());
EXPECT_FALSE(observer_.is_supported_.value());
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS); EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS);
EXPECT_TRUE(observer_.update_.has(ACCELEROMETER_SOURCE_SCREEN)); EXPECT_TRUE(observer_.update_.has(ACCELEROMETER_SOURCE_SCREEN));
...@@ -190,11 +204,13 @@ TEST_F(AccelerometerProviderMojoTest, GetSamplesWithLidAngle) { ...@@ -190,11 +204,13 @@ TEST_F(AccelerometerProviderMojoTest, GetSamplesWithLidAngle) {
chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer( chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer(
sensor_hal_server_->PassRemote()); sensor_hal_server_->PassRemote());
// Wait until all setups are finished and the one time read is done. // Wait until all setups are finished and no samples updated.
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_TRUE(observer_.is_supported_.has_value());
EXPECT_TRUE(observer_.is_supported_.value());
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS); EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS);
EXPECT_TRUE(observer_.update_.has(ACCELEROMETER_SOURCE_SCREEN)); EXPECT_FALSE(observer_.update_.has(ACCELEROMETER_SOURCE_SCREEN));
EXPECT_FALSE(observer_.update_.has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)); EXPECT_FALSE(observer_.update_.has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD));
observer_.update_.Reset(); observer_.update_.Reset();
......
...@@ -8,9 +8,12 @@ ...@@ -8,9 +8,12 @@
#include "ash/accelerometer/accelerometer_file_reader.h" #include "ash/accelerometer/accelerometer_file_reader.h"
#include "ash/accelerometer/accelerometer_provider_mojo.h" #include "ash/accelerometer/accelerometer_provider_mojo.h"
#include "ash/shell.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/posix/eintr_wrapper.h" #include "base/posix/eintr_wrapper.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/task/current_thread.h"
#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/sequenced_task_runner_handle.h"
namespace ash { namespace ash {
...@@ -52,10 +55,6 @@ void AccelerometerReader::SetEnabled(bool enabled) { ...@@ -52,10 +55,6 @@ void AccelerometerReader::SetEnabled(bool enabled) {
accelerometer_provider_->SetEmitEvents(enabled); accelerometer_provider_->SetEmitEvents(enabled);
} }
ECLidAngleDriverStatus AccelerometerReader::GetECLidAngleDriverStatus() const {
return accelerometer_provider_->GetECLidAngleDriverStatus();
}
void AccelerometerReader::SetECLidAngleDriverStatusForTesting( void AccelerometerReader::SetECLidAngleDriverStatusForTesting(
ECLidAngleDriverStatus ec_lid_angle_driver_status) { ECLidAngleDriverStatus ec_lid_angle_driver_status) {
accelerometer_provider_->SetECLidAngleDriverStatusForTesting( // IN-TEST accelerometer_provider_->SetECLidAngleDriverStatusForTesting( // IN-TEST
...@@ -78,14 +77,110 @@ AccelerometerReader::AccelerometerReader() { ...@@ -78,14 +77,110 @@ AccelerometerReader::AccelerometerReader() {
AccelerometerReader::~AccelerometerReader() = default; AccelerometerReader::~AccelerometerReader() = default;
void AccelerometerProviderInterface::OnTabletPhysicalStateChanged() {
DCHECK(base::CurrentUIThread::IsSet());
if (ShouldDelayOnTabletPhysicalStateChanged())
return;
// When CrOS EC lid angle driver is not present, accelerometer read is always
// ON and can't be tuned. Thus this object no longer listens to tablet mode
// event.
auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller();
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::NOT_SUPPORTED) {
tablet_mode_controller->RemoveObserver(this);
return;
}
// Auto rotation is turned on when the device is physically used as a tablet
// (i.e. flipped or detached), regardless of the UI state (i.e. whether tablet
// mode is turned on or off).
if (tablet_mode_controller->is_in_tablet_physical_state())
TriggerRead();
else
CancelRead();
}
void AccelerometerProviderInterface::AddObserver(
AccelerometerReader::Observer* observer) {
DCHECK(base::CurrentUIThread::IsSet());
if (ec_lid_angle_driver_status_ != ECLidAngleDriverStatus::UNKNOWN) {
observer->OnECLidAngleDriverStatusChanged(
ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::SUPPORTED);
}
observers_.AddObserver(observer);
}
void AccelerometerProviderInterface::RemoveObserver(
AccelerometerReader::Observer* observer) {
DCHECK(base::CurrentUIThread::IsSet());
observers_.RemoveObserver(observer);
}
void AccelerometerProviderInterface::StartListenToTabletModeController() {
Shell::Get()->tablet_mode_controller()->AddObserver(this);
}
void AccelerometerProviderInterface::StopListenToTabletModeController() {
Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
}
void AccelerometerProviderInterface::SetEmitEvents(bool emit_events) {
DCHECK(base::CurrentUIThread::IsSet());
emit_events_ = emit_events;
}
void AccelerometerProviderInterface::SetECLidAngleDriverStatusForTesting(
ECLidAngleDriverStatus status) {
SetECLidAngleDriverStatus(status);
}
AccelerometerProviderInterface::AccelerometerProviderInterface()
: ui_task_runner_(base::SequencedTaskRunnerHandle::Get()) {
DCHECK(base::CurrentUIThread::IsSet());
}
AccelerometerProviderInterface::~AccelerometerProviderInterface() = default;
bool AccelerometerProviderInterface::ShouldDelayOnTabletPhysicalStateChanged() {
return false;
}
void AccelerometerProviderInterface::SetECLidAngleDriverStatus(
ECLidAngleDriverStatus status) {
DCHECK(base::CurrentUIThread::IsSet());
DCHECK_NE(status, ECLidAngleDriverStatus::UNKNOWN);
if (status == ec_lid_angle_driver_status_)
return;
ec_lid_angle_driver_status_ = status;
for (auto& observer : observers_) {
observer.OnECLidAngleDriverStatusChanged(ec_lid_angle_driver_status_ ==
ECLidAngleDriverStatus::SUPPORTED);
}
}
ECLidAngleDriverStatus ECLidAngleDriverStatus
AccelerometerProviderInterface::GetECLidAngleDriverStatus() const { AccelerometerProviderInterface::GetECLidAngleDriverStatus() const {
DCHECK(base::CurrentUIThread::IsSet());
return ec_lid_angle_driver_status_; return ec_lid_angle_driver_status_;
} }
void AccelerometerProviderInterface::SetECLidAngleDriverStatusForTesting( void AccelerometerProviderInterface::NotifyAccelerometerUpdated(
ECLidAngleDriverStatus ec_lid_angle_driver_status) { const AccelerometerUpdate& update) {
ec_lid_angle_driver_status_ = ec_lid_angle_driver_status; DCHECK(base::CurrentUIThread::IsSet());
DCHECK_NE(ec_lid_angle_driver_status_, ECLidAngleDriverStatus::UNKNOWN);
if (!emit_events_)
return;
for (auto& observer : observers_)
observer.OnAccelerometerUpdated(update);
} }
} // namespace ash } // namespace ash
...@@ -7,8 +7,10 @@ ...@@ -7,8 +7,10 @@
#include "ash/accelerometer/accelerometer_types.h" #include "ash/accelerometer/accelerometer_types.h"
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/public/cpp/tablet_mode_observer.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/observer_list.h"
namespace base { namespace base {
template <typename T> template <typename T>
...@@ -39,6 +41,11 @@ class ASH_EXPORT AccelerometerReader { ...@@ -39,6 +41,11 @@ class ASH_EXPORT AccelerometerReader {
// An interface to receive data from the AccelerometerReader. // An interface to receive data from the AccelerometerReader.
class Observer { class Observer {
public: public:
// Called only once, when
// |AcceleromterProviderInterface::ec_lid_angle_driver_status_| is set to
// either SUPPORTED or NOT_SUPPORTED.
// It's also guaranteed to be called before |OnAccelerometerUpdated|.
virtual void OnECLidAngleDriverStatusChanged(bool is_supported) = 0;
virtual void OnAccelerometerUpdated(const AccelerometerUpdate& update) = 0; virtual void OnAccelerometerUpdated(const AccelerometerUpdate& update) = 0;
protected: protected:
...@@ -62,9 +69,6 @@ class ASH_EXPORT AccelerometerReader { ...@@ -62,9 +69,6 @@ class ASH_EXPORT AccelerometerReader {
// be able to control the accelerometer feature. // be able to control the accelerometer feature.
void SetEnabled(bool enabled); void SetEnabled(bool enabled);
// Return the state of the driver being supported or not.
ECLidAngleDriverStatus GetECLidAngleDriverStatus() const;
void SetECLidAngleDriverStatusForTesting( void SetECLidAngleDriverStatusForTesting(
ECLidAngleDriverStatus ec_lid_angle_driver_status); ECLidAngleDriverStatus ec_lid_angle_driver_status);
...@@ -83,41 +87,71 @@ class ASH_EXPORT AccelerometerReader { ...@@ -83,41 +87,71 @@ class ASH_EXPORT AccelerometerReader {
scoped_refptr<AccelerometerProviderInterface> accelerometer_provider_; scoped_refptr<AccelerometerProviderInterface> accelerometer_provider_;
}; };
class AccelerometerProviderInterface class ASH_EXPORT AccelerometerProviderInterface
: public base::RefCountedThreadSafe<AccelerometerProviderInterface> { : public base::RefCountedThreadSafe<AccelerometerProviderInterface>,
public TabletModeObserver {
public: public:
// Prepare and start async initialization. // Prepare and start async initialization.
virtual void PrepareAndInitialize() = 0; virtual void PrepareAndInitialize() = 0;
// With ChromeOS EC lid angle driver present, it's triggered when the device
// is physically used as a tablet (even thought its UI might be in clamshell
// mode), cancelled otherwise.
virtual void TriggerRead() = 0;
virtual void CancelRead() = 0;
// TabletModeObserver:
void OnTabletPhysicalStateChanged() override;
// Add/Remove observers. // Add/Remove observers.
virtual void AddObserver(AccelerometerReader::Observer* observer) = 0; void AddObserver(AccelerometerReader::Observer* observer);
virtual void RemoveObserver(AccelerometerReader::Observer* observer) = 0; void RemoveObserver(AccelerometerReader::Observer* observer);
// Start/Stop listening to tablet mode controller. // Start/Stop listening to tablet mode controller.
virtual void StartListenToTabletModeController() = 0; void StartListenToTabletModeController();
virtual void StopListenToTabletModeController() = 0; void StopListenToTabletModeController();
// Set emitting events (samples) to observers or not. // Set emitting events (samples) to observers or not.
virtual void SetEmitEvents(bool emit_events) = 0; void SetEmitEvents(bool emit_events);
void SetECLidAngleDriverStatusForTesting(ECLidAngleDriverStatus status);
// Return the state of the driver being supported or not. protected:
AccelerometerProviderInterface();
~AccelerometerProviderInterface() override;
// Used in |OnTabletPhysicalStateChanged()|. As there might be
// initialization steps, each implementation can override this function to
// determine if this class is ready to process the state changed.
// If returns true, |OnTabletPhysicalStateChanged()| will be skipped, and it's
// the implementation's responsibility to call it again when the class is
// ready. If returns false, |OnTabletPhysicalStateChanged()| will be processed
// as usual.
// Default to return false.
virtual bool ShouldDelayOnTabletPhysicalStateChanged();
void SetECLidAngleDriverStatus(ECLidAngleDriverStatus status);
ECLidAngleDriverStatus GetECLidAngleDriverStatus() const; ECLidAngleDriverStatus GetECLidAngleDriverStatus() const;
void SetECLidAngleDriverStatusForTesting( void NotifyAccelerometerUpdated(const AccelerometerUpdate& update);
ECLidAngleDriverStatus ec_lid_angle_driver_status);
protected: // Set in the constructor.
virtual ~AccelerometerProviderInterface() = default; scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
// The current initialization state of reader. // The current initialization state of reader.
State initialization_state_ = State::INITIALIZING; State initialization_state_ = State::INITIALIZING;
private:
// State of ChromeOS EC lid angle driver, if SUPPORTED, it means EC can handle // State of ChromeOS EC lid angle driver, if SUPPORTED, it means EC can handle
// lid angle calculation. // lid angle calculation.
ECLidAngleDriverStatus ec_lid_angle_driver_status_ = ECLidAngleDriverStatus ec_lid_angle_driver_status_ =
ECLidAngleDriverStatus::UNKNOWN; ECLidAngleDriverStatus::UNKNOWN;
private: bool emit_events_ = true;
// The observers to notify of accelerometer updates.
// Bound to the UI thread.
base::ObserverList<AccelerometerReader::Observer>::Unchecked observers_;
friend class base::RefCountedThreadSafe<AccelerometerProviderInterface>; friend class base::RefCountedThreadSafe<AccelerometerProviderInterface>;
}; };
......
...@@ -152,6 +152,7 @@ class ASH_EXPORT ScreenOrientationController ...@@ -152,6 +152,7 @@ class ASH_EXPORT ScreenOrientationController
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
// AccelerometerReader::Observer: // AccelerometerReader::Observer:
void OnECLidAngleDriverStatusChanged(bool is_supported) override {}
void OnAccelerometerUpdated(const AccelerometerUpdate& update) override; void OnAccelerometerUpdated(const AccelerometerUpdate& update) override;
// WindowTreeHostManager::Observer: // WindowTreeHostManager::Observer:
......
...@@ -138,6 +138,7 @@ class ASH_EXPORT PowerButtonController ...@@ -138,6 +138,7 @@ class ASH_EXPORT PowerButtonController
// TODO(minch): Remove this if/when all applicable devices expose a tablet // TODO(minch): Remove this if/when all applicable devices expose a tablet
// mode switch: https://crbug.com/798646. // mode switch: https://crbug.com/798646.
// AccelerometerReader::Observer: // AccelerometerReader::Observer:
void OnECLidAngleDriverStatusChanged(bool is_supported) override {}
void OnAccelerometerUpdated(const AccelerometerUpdate& update) override; void OnAccelerometerUpdated(const AccelerometerUpdate& update) override;
// BacklightsForcedOffSetter::Observer: // BacklightsForcedOffSetter::Observer:
......
...@@ -627,27 +627,27 @@ void TabletModeController::OnChromeTerminating() { ...@@ -627,27 +627,27 @@ void TabletModeController::OnChromeTerminating() {
} }
} }
void TabletModeController::OnAccelerometerUpdated( void TabletModeController::OnECLidAngleDriverStatusChanged(bool is_supported) {
const AccelerometerUpdate& update) { is_ec_lid_angle_driver_supported_ = is_supported;
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::UNKNOWN) {
ec_lid_angle_driver_status_ =
AccelerometerReader::GetInstance()->GetECLidAngleDriverStatus();
}
// When ChromeOS EC lid angle driver is present, EC can handle lid angle if (!is_supported)
// calculation, thus Chrome side lid angle calculation is disabled. In this
// case, TabletModeController no longer listens to accelerometer events.
if (ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::SUPPORTED) {
// Reset lid angle that might be calculated before lid angle driver is
// read.
lid_angle_ = 0.f;
can_detect_lid_angle_ = false;
if (record_lid_angle_timer_.IsRunning())
record_lid_angle_timer_.Stop();
AccelerometerReader::GetInstance()->RemoveObserver(this);
return; return;
}
// When ChromeOS EC lid angle driver is supported, EC can handle lid angle
// calculation, thus Chrome side lid angle calculation is disabled. In this
// case, TabletModeController no longer listens to accelerometer samples.
// Reset lid angle that might be calculated before lid angle driver is
// read.
lid_angle_ = 0.f;
can_detect_lid_angle_ = false;
if (record_lid_angle_timer_.IsRunning())
record_lid_angle_timer_.Stop();
AccelerometerReader::GetInstance()->RemoveObserver(this);
}
void TabletModeController::OnAccelerometerUpdated(
const AccelerometerUpdate& update) {
have_seen_accelerometer_data_ = true; have_seen_accelerometer_data_ = true;
can_detect_lid_angle_ = update.has(ACCELEROMETER_SOURCE_SCREEN) && can_detect_lid_angle_ = update.has(ACCELEROMETER_SOURCE_SCREEN) &&
update.has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD); update.has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD);
...@@ -1300,7 +1300,7 @@ bool TabletModeController::ShouldUiBeInTabletMode() const { ...@@ -1300,7 +1300,7 @@ bool TabletModeController::ShouldUiBeInTabletMode() const {
const bool can_enter_tablet_mode = const bool can_enter_tablet_mode =
IsBoardTypeMarkedAsTabletCapable() && HasActiveInternalDisplay() && IsBoardTypeMarkedAsTabletCapable() && HasActiveInternalDisplay() &&
(ec_lid_angle_driver_status_ == ECLidAngleDriverStatus::SUPPORTED || (is_ec_lid_angle_driver_supported_.value_or(false) ||
have_seen_accelerometer_data_); have_seen_accelerometer_data_);
return !has_internal_pointing_device_ && can_enter_tablet_mode && return !has_internal_pointing_device_ && can_enter_tablet_mode &&
......
...@@ -147,6 +147,7 @@ class ASH_EXPORT TabletModeController ...@@ -147,6 +147,7 @@ class ASH_EXPORT TabletModeController
void OnChromeTerminating() override; void OnChromeTerminating() override;
// AccelerometerReader::Observer: // AccelerometerReader::Observer:
void OnECLidAngleDriverStatusChanged(bool is_supported) override;
void OnAccelerometerUpdated(const AccelerometerUpdate& update) override; void OnAccelerometerUpdated(const AccelerometerUpdate& update) override;
// chromeos::PowerManagerClient::Observer: // chromeos::PowerManagerClient::Observer:
...@@ -351,15 +352,17 @@ class ASH_EXPORT TabletModeController ...@@ -351,15 +352,17 @@ class ASH_EXPORT TabletModeController
// internal keyboard and touchpad. // internal keyboard and touchpad.
std::unique_ptr<InternalInputDevicesEventBlocker> event_blocker_; std::unique_ptr<InternalInputDevicesEventBlocker> event_blocker_;
// Whether we have ever seen accelerometer data. When ChromeOS EC lid angle is // Whether we have ever seen accelerometer data. When ChromeOS EC lid angle
// present, convertible device cannot see accelerometer data. // driver is supported, convertible device cannot see accelerometer data.
bool have_seen_accelerometer_data_ = false; bool have_seen_accelerometer_data_ = false;
// If ECLidAngleDriverStatus is supported, Chrome does not calculate lid angle // If ECLidAngleDriverStatus is supported, Chrome does not calculate lid angle
// itself, but will reply on the tablet-mode flag that EC sends to decide if // itself, but will rely on the tablet-mode flag that EC sends to decide if
// the device should in tablet mode. // the device should in tablet mode.
ECLidAngleDriverStatus ec_lid_angle_driver_status_ = // As it's set in |OnECLidAngleDriverStatusChanged|, which is a callback by
ECLidAngleDriverStatus::UNKNOWN; // AccelerometerReader, we make it optional to indicate a lack of value until
// the accelerometer reader is initialized.
base::Optional<bool> is_ec_lid_angle_driver_supported_;
// Whether the lid angle can be detected by browser. If it's true, the device // Whether the lid angle can be detected by browser. If it's true, the device
// is a convertible device (both screen acclerometer and keyboard acclerometer // is a convertible device (both screen acclerometer and keyboard acclerometer
......
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