blob: 4dcc6cce4239d453dde70633e8c6f698a39d3dec [file] [log] [blame]
// Copyright 2019 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.
#include "chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.h"
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_context_menu/accessibility_labels_bubble_model.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
#include "chrome/browser/ui/confirm_bubble.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/context_menu_params.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/rect.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#else
#include "content/public/browser/browser_accessibility_state.h"
#endif // defined(OS_CHROMEOS)
using content::BrowserThread;
AccessibilityLabelsMenuObserver::AccessibilityLabelsMenuObserver(
RenderViewContextMenuProxy* proxy)
: proxy_(proxy) {}
AccessibilityLabelsMenuObserver::~AccessibilityLabelsMenuObserver() {}
void AccessibilityLabelsMenuObserver::InitMenu(
const content::ContextMenuParams& params) {
Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
if (ShouldShowLabelsItem()) {
proxy_->AddAccessibilityLabelsServiceItem(profile->GetPrefs()->GetBoolean(
prefs::kAccessibilityImageLabelsEnabled));
}
}
bool AccessibilityLabelsMenuObserver::IsCommandIdSupported(int command_id) {
return command_id == IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE;
}
bool AccessibilityLabelsMenuObserver::IsCommandIdChecked(int command_id) {
DCHECK(IsCommandIdSupported(command_id));
Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
if (command_id == IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE) {
return profile->GetPrefs()->GetBoolean(
prefs::kAccessibilityImageLabelsEnabled);
}
return false;
}
bool AccessibilityLabelsMenuObserver::IsCommandIdEnabled(int command_id) {
DCHECK(IsCommandIdSupported(command_id));
if (command_id == IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE) {
return ShouldShowLabelsItem();
}
return false;
}
void AccessibilityLabelsMenuObserver::ExecuteCommand(int command_id) {
// TODO(katie): Add logging.
DCHECK(IsCommandIdSupported(command_id));
Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
if (command_id == IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE) {
// When a user enables the accessibility labeling item, we
// show a bubble to confirm it. On the other hand, when a user disables this
// item, we directly update/ the profile and stop integrating the labels
// service immediately.
if (!profile->GetPrefs()->GetBoolean(
prefs::kAccessibilityImageLabelsEnabled)) {
content::RenderViewHost* rvh = proxy_->GetRenderViewHost();
gfx::Rect rect = rvh->GetWidget()->GetView()->GetViewBounds();
std::unique_ptr<AccessibilityLabelsBubbleModel> model(
new AccessibilityLabelsBubbleModel(profile,
proxy_->GetWebContents()));
chrome::ShowConfirmBubble(
proxy_->GetWebContents()->GetTopLevelNativeWindow(),
rvh->GetWidget()->GetView()->GetNativeView(),
gfx::Point(rect.CenterPoint().x(), rect.y()), std::move(model));
} else {
if (profile) {
profile->GetPrefs()->SetBoolean(prefs::kAccessibilityImageLabelsEnabled,
false);
}
}
}
}
bool AccessibilityLabelsMenuObserver::ShouldShowLabelsItem() {
// Hidden behind a feature flag.
base::CommandLine& cmd = *base::CommandLine::ForCurrentProcess();
if (!cmd.HasSwitch(::switches::kEnableExperimentalAccessibilityLabels)) {
return false;
}
// Check if a screen reader is running.
#if defined(OS_CHROMEOS)
return chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled();
#else
// TODO(katie): Can we use AXMode in Chrome OS as well?
ui::AXMode mode =
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
return mode.has_mode(ui::AXMode::kScreenReader);
#endif // defined(OS_CHROMEOS)
}