// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef ASH_ACCELEROMETER_ACCELEROMETER_READER_H_ #define ASH_ACCELEROMETER_ACCELEROMETER_READER_H_ #include "ash/accelerometer/accelerometer_types.h" #include "ash/ash_export.h" #include "ash/public/cpp/tablet_mode_observer.h" #include "base/memory/ref_counted.h" #include "base/no_destructor.h" #include "base/observer_list.h" namespace base { class SequencedTaskRunner; } // namespace base namespace ash { enum class ECLidAngleDriverStatus { UNKNOWN, SUPPORTED, NOT_SUPPORTED }; class AccelerometerProviderInterface; // AccelerometerReader should only be used on the UI thread. // It notifies observers if EC Lid Angle Driver is supported, and provides // accelerometers' (lid and base) samples. // The current usages of accelerometers' samples are for calculating the angle // between the lid and the base, which can be substituted by EC Lid Angle // Driver, if it exists, and the auto rotation, which only needs // lid-accelerometer's data. // Therefore, if EC Lid Angle Driver is present, base-accelerometer's samples // may be ignored and not sent to the observers. class ASH_EXPORT AccelerometerReader { public: // An interface to receive data from the AccelerometerReader. class Observer { public: // Normally called only once, when // |AcceleromterProviderInterface::ec_lid_angle_driver_status_| is set to // either SUPPORTED or NOT_SUPPORTED, unless the lid angle driver is // late-present after timed out, which will be called twice with // |is_supported| being false and true respectively. // It's guaranteed to be called before |OnAccelerometerUpdated|. virtual void OnECLidAngleDriverStatusChanged(bool is_supported) = 0; virtual void OnAccelerometerUpdated(const AccelerometerUpdate& update) = 0; protected: virtual ~Observer() {} }; static AccelerometerReader* GetInstance(); void Initialize(); // Add/Remove observers. void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); // Accelerometer file reader starts/stops listening to tablet mode controller. void StartListenToTabletModeController(); void StopListenToTabletModeController(); // Controls the availability of emitting acccelerometer reader events to // its observers. This shouldn't be called normally, but Tast tests should // be able to control the accelerometer feature. void SetEnabled(bool enabled); void SetECLidAngleDriverStatusForTesting( ECLidAngleDriverStatus ec_lid_angle_driver_status); protected: AccelerometerReader(); AccelerometerReader(const AccelerometerReader&) = delete; AccelerometerReader& operator=(const AccelerometerReader&) = delete; virtual ~AccelerometerReader(); private: friend class base::NoDestructor; // Worker that will run on the base::SequencedTaskRunner provided to // Initialize. It will determine accelerometer configuration, read the data, // and notify observers. scoped_refptr accelerometer_provider_; }; class ASH_EXPORT AccelerometerProviderInterface : public base::RefCountedThreadSafe, public TabletModeObserver { public: // Prepare and start async initialization. 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. void AddObserver(AccelerometerReader::Observer* observer); void RemoveObserver(AccelerometerReader::Observer* observer); // Start/Stop listening to tablet mode controller. void StartListenToTabletModeController(); void StopListenToTabletModeController(); // Set emitting events (samples) to observers or not. void SetEmitEvents(bool emit_events); void SetECLidAngleDriverStatusForTesting(ECLidAngleDriverStatus status); 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; void NotifyAccelerometerUpdated(const AccelerometerUpdate& update); // Set in the constructor. scoped_refptr ui_task_runner_; private: // State of ChromeOS EC lid angle driver, if SUPPORTED, it means EC can handle // lid angle calculation. ECLidAngleDriverStatus ec_lid_angle_driver_status_ = ECLidAngleDriverStatus::UNKNOWN; bool emit_events_ = true; // The observers to notify of accelerometer updates. // Bound to the UI thread. base::ObserverList::Unchecked observers_; friend class base::RefCountedThreadSafe; }; } // namespace ash #endif // ASH_ACCELEROMETER_ACCELEROMETER_READER_H_