// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/accelerometer/accelerometer_reader.h"
#include "ash/shell.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/no_destructor.h"
#include "base/task/current_thread.h"
#include "base/task/sequenced_task_runner.h"
#include "ash/accelerometer/accelerometer_provider_mojo.h"
namespace ash {
// static
AccelerometerReader* AccelerometerReader::GetInstance() {
static base::NoDestructor<AccelerometerReader> accelerometer_reader;
return accelerometer_reader.get();
}
void AccelerometerReader::Initialize() {
accelerometer_provider_->PrepareAndInitialize();
}
void AccelerometerReader::AddObserver(Observer* observer) {
accelerometer_provider_->AddObserver(observer);
}
void AccelerometerReader::RemoveObserver(Observer* observer) {
accelerometer_provider_->RemoveObserver(observer);
}
void AccelerometerReader::StartListenToTabletModeController() {
accelerometer_provider_->StartListenToTabletModeController();
}
void AccelerometerReader::StopListenToTabletModeController() {
accelerometer_provider_->StopListenToTabletModeController();
}
void AccelerometerReader::SetEnabled(bool enabled) {
accelerometer_provider_->SetEmitEvents(enabled);
}
void AccelerometerReader::SetECLidAngleDriverStatusForTesting(
ECLidAngleDriverStatus ec_lid_angle_driver_status) {
accelerometer_provider_->SetECLidAngleDriverStatusForTesting( // IN-TEST
ec_lid_angle_driver_status);
}
AccelerometerReader::AccelerometerReader() {
accelerometer_provider_ = new AccelerometerProviderMojo();
}
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::SequencedTaskRunner::GetCurrentDefault()) {
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
AccelerometerProviderInterface::GetECLidAngleDriverStatus() const {
DCHECK(base::CurrentUIThread::IsSet());
return ec_lid_angle_driver_status_;
}
void AccelerometerProviderInterface::NotifyAccelerometerUpdated(
const AccelerometerUpdate& update) {
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