blob: 95e488467cf7adc3c9cf09ed9890a9e8eed4f22a [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_STATE_IMPL_H_
#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_STATE_IMPL_H_
#include <memory>
#include <vector>
#include "base/time/time.h"
#include "components/metrics/metrics_provider.h"
#include "content/browser/accessibility/scoped_mode_collection.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "ui/accessibility/ax_mode.h"
#include "ui/accessibility/platform/ax_platform.h"
namespace content {
struct FocusedNodeDetails;
// The BrowserAccessibilityState class is used to determine if Chrome should be
// customized for users with assistive technology, such as screen readers. We
// modify the behavior of certain user interfaces to provide a better experience
// for screen reader users. The way we detect a screen reader program is
// different for each platform.
//
// Screen Reader Detection
// (1) On Windows, many screen reader detection mechanisms will give false
// positives, such as relying on the SPI_GETSCREENREADER system parameter.
// In Chrome, we attempt to dynamically detect a MSAA client screen reader
// by calling NotifyWinEvent in NativeWidgetWin with a custom ID and wait
// to see if the ID is requested by a subsequent call to WM_GETOBJECT.
// (2) On macOS, we dynamically detect if VoiceOver is running by Key-Value
// Observing changes to the "voiceOverEnabled" property in NSWorkspace. We
// also monitor the undocumented accessibility attribute
// @"AXEnhancedUserInterface", which is set by other assistive
// technologies.
class CONTENT_EXPORT BrowserAccessibilityStateImpl
: public BrowserAccessibilityState,
public ui::AXPlatform::Delegate {
public:
BrowserAccessibilityStateImpl(const BrowserAccessibilityStateImpl&) = delete;
BrowserAccessibilityStateImpl& operator=(
const BrowserAccessibilityStateImpl&) = delete;
~BrowserAccessibilityStateImpl() override;
// Returns the single process-wide instance.
static BrowserAccessibilityStateImpl* GetInstance();
// Returns a new instance. Only one instance may be live in the process at any
// time.
static std::unique_ptr<BrowserAccessibilityStateImpl> Create();
// This needs to be called explicitly by content::BrowserMainLoop during
// initialization, in order to schedule tasks that need to be done, but
// don't need to block the main thread.
//
// This is called explicitly and not automatically just by
// instantiating this class so that tests can use
// BrowserAccessibilityState without worrying about threading.
virtual void InitBackgroundTasks();
// BrowserAccessibilityState implementation.
void EnableAccessibility() override;
void DisableAccessibility() override;
bool IsRendererAccessibilityEnabled() override;
ui::AXMode GetAccessibilityMode() override;
ui::AXMode GetAccessibilityModeForBrowserContext(
BrowserContext* browser_context) override;
void AddAccessibilityModeFlags(ui::AXMode mode) override;
void RemoveAccessibilityModeFlags(ui::AXMode mode) override;
void ResetAccessibilityMode() override;
void OnScreenReaderDetected() override;
void OnScreenReaderStopped() override;
bool IsAccessibleBrowser() override;
void AddUIThreadHistogramCallback(base::OnceClosure callback) override;
void AddOtherThreadHistogramCallback(base::OnceClosure callback) override;
void UpdateUniqueUserHistograms() override;
void UpdateHistogramsForTesting() override;
void SetPerformanceFilteringAllowed(bool enabled) override;
bool IsPerformanceFilteringAllowed() override;
base::CallbackListSubscription RegisterFocusChangedCallback(
FocusChangedCallback callback) override;
std::unique_ptr<ScopedAccessibilityMode> CreateScopedModeForProcess(
ui::AXMode mode) override;
std::unique_ptr<ScopedAccessibilityMode> CreateScopedModeForBrowserContext(
BrowserContext* browser_context,
ui::AXMode mode) override;
std::unique_ptr<ScopedAccessibilityMode> CreateScopedModeForWebContents(
WebContents* web_contents,
ui::AXMode mode) override;
void SetAXModeChangeAllowed(bool allowed) override;
bool IsAXModeChangeAllowed() const override;
// ui::AXPlatform::Delegate:
ui::AXMode GetProcessMode() override;
void SetProcessMode(ui::AXMode new_mode) override;
void OnAccessibilityApiUsage() override;
// The global accessibility mode is automatically enabled based on
// usage of accessibility APIs. When we detect a significant amount
// of user inputs within a certain time period, but no accessibility
// API usage, we automatically disable accessibility.
void OnUserInputEvent();
// Calls InitBackgroundTasks with short delays for scheduled tasks,
// and then calls the given completion callback when done.
void CallInitBackgroundTasksForTesting(base::RepeatingClosure done_callback);
// Notifies listeners that the focused element changed inside a WebContents.
void OnFocusChangedInPage(const FocusedNodeDetails& details);
protected:
BrowserAccessibilityStateImpl();
// Called a short while after startup to allow time for the accessibility
// state to be determined. Updates histograms with the current state.
// Two variants - one for things that must be run on the UI thread, and
// another that can be run on another thread.
virtual void UpdateHistogramsOnUIThread();
virtual void UpdateHistogramsOnOtherThread();
private:
// Called by `OnScreenReaderStopped` as a delayed task. If accessibility
// support has not been re-enabled by the time the delay has expired, we clear
// `process_accessibility_mode_` so that all WebContentses are updated.
void MaybeResetAccessibilityMode();
void OnOtherThreadDone();
void UpdateAccessibilityActivityTask();
// Handles a change to the effective accessibility mode for the process.
void OnModeChangedForProcess(ui::AXMode old_mode, ui::AXMode new_mode);
// Handles a change to the effective accessibility mode for `browser_context`.
void OnModeChangedForBrowserContext(BrowserContext* browser_context,
ui::AXMode old_mode,
ui::AXMode new_mode);
// Handles a change to the effective accessibility mode for `web_contents`.
void OnModeChangedForWebContents(WebContents* web_contents,
ui::AXMode old_mode,
ui::AXMode new_mode);
// The process's single AXPlatform instance.
ui::AXPlatform ax_platform_;
base::TimeDelta histogram_delay_;
std::vector<base::OnceClosure> ui_thread_histogram_callbacks_;
std::vector<base::OnceClosure> other_thread_histogram_callbacks_;
bool ui_thread_done_ = false;
bool other_thread_done_ = false;
base::RepeatingClosure background_thread_done_callback_;
// Whether there is a pending task to run UpdateAccessibilityActivityTask.
bool accessibility_update_task_pending_ = false;
// Whether changes to the AXMode are allowed.
// Changes are disallowed while running tests or when
// --force-renderer-accessibility is used on the command line.
bool allow_ax_mode_changes_ = true;
// Keeps track of whether performance filtering is allowed for the device.
// Default is true to defer to feature flag. Value may be set to false by
// prefs.
bool performance_filtering_allowed_ = true;
// The time of the first user input event; if we receive multiple
// user input events within a 30-second period and no
base::TimeTicks first_user_input_event_time_;
int user_input_event_count_ = 0;
// The time accessibility became active, used to calculate active time.
base::TimeTicks accessibility_active_start_time_;
// The time accessibility became inactive, used to calculate inactive time.
base::TimeTicks accessibility_inactive_start_time_;
// The last time accessibility was active, used to calculate active time.
base::TimeTicks accessibility_last_usage_time_;
// The time accessibility was enabled, for statistics.
base::TimeTicks accessibility_enabled_time_;
// The time accessibility was auto-disabled, for statistics.
base::TimeTicks accessibility_disabled_time_;
// The time of the most-recent, explicit request to disable accessibility
// support. This is set in `OnScreenReaderStopped`. We keep track of this
// in order to prevent destroying and/or (re)creating large accessibility
// trees in response to an assistive technology being toggled.
base::TimeTicks disable_accessibility_request_time_;
base::RepeatingCallbackList<void(const FocusedNodeDetails&)>
focus_changed_callbacks_;
// The collection of active ScopedAccessibilityMode instances targeting all
// WebContentses in the process.
ScopedModeCollection scoped_modes_for_process_;
// A ScopedAccessibilityMode that holds the process-wide mode flags modified
// via ui::AXPlatformNode::NotifyAddAXModeFlags(),
// AddAccessibilityModeFlags(), RemoveAccessibilityModeFlags(), and
// ResetAccessibilityMode(); and applies them to all WebContentses in the
// process. Guaranteed to hold at least an instance with no mode flags set.
std::unique_ptr<ScopedAccessibilityMode> process_accessibility_mode_;
base::WeakPtrFactory<BrowserAccessibilityStateImpl> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_STATE_IMPL_H_