| // Copyright (c) 2018 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 "chromecast/browser/extensions/api/accessibility_private/accessibility_extension_api.h" |
| |
| #include "base/logging.h" |
| #include "chromecast/browser/accessibility/accessibility_manager.h" |
| #include "chromecast/browser/cast_browser_process.h" |
| #include "chromecast/common/extensions_api/accessibility_private.h" |
| #include "content/public/browser/browser_accessibility_state.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "extensions/common/image_util.h" |
| #include "services/service_manager/public/cpp/interface_provider.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/display/display.h" |
| #include "ui/display/screen.h" |
| #include "ui/events/base_event_utils.h" |
| #include "ui/events/event.h" |
| #include "ui/events/event_constants.h" |
| |
| namespace { |
| |
| const char kErrorNotSupported[] = "This API is not supported on this platform."; |
| |
| } // namespace |
| |
| namespace extensions { |
| namespace cast { |
| namespace api { |
| |
| ExtensionFunction::ResponseAction |
| AccessibilityPrivateSetNativeAccessibilityEnabledFunction::Run() { |
| EXTENSION_FUNCTION_VALIDATE(args().size() >= 1); |
| EXTENSION_FUNCTION_VALIDATE(args()[0].is_bool()); |
| bool enabled = args()[0].GetBool(); |
| if (enabled) { |
| content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); |
| } else { |
| content::BrowserAccessibilityState::GetInstance()->DisableAccessibility(); |
| } |
| return RespondNow(NoArguments()); |
| } |
| |
| ExtensionFunction::ResponseAction |
| AccessibilityPrivateSetFocusRingsFunction::Run() { |
| std::unique_ptr<accessibility_private::SetFocusRings::Params> params( |
| accessibility_private::SetFocusRings::Params::Create(args())); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| auto* accessibility_manager = |
| chromecast::shell::CastBrowserProcess::GetInstance() |
| ->accessibility_manager(); |
| |
| for (const accessibility_private::FocusRingInfo& focus_ring_info : |
| params->focus_rings) { |
| std::vector<gfx::Rect> rects; |
| for (const accessibility_private::ScreenRect& rect : |
| focus_ring_info.rects) { |
| rects.push_back(gfx::Rect(rect.left, rect.top, rect.width, rect.height)); |
| } |
| |
| if (focus_ring_info.color.length() > 0) { |
| SkColor color; |
| if (!extensions::image_util::ParseHexColorString(focus_ring_info.color, |
| &color)) |
| return RespondNow(Error("Could not parse hex color")); |
| accessibility_manager->SetFocusRingColor(color); |
| } else { |
| accessibility_manager->ResetFocusRingColor(); |
| } |
| |
| // Move the visible focus ring to cover all of these rects. |
| accessibility_manager->SetFocusRing( |
| rects, chromecast::FocusRingBehavior::PERSIST_FOCUS_RING); |
| |
| // Also update the touch exploration controller so that synthesized |
| // touch events are anchored within the focused object. |
| if (!rects.empty()) { |
| accessibility_manager->SetTouchAccessibilityAnchorPoint( |
| rects[0].CenterPoint()); |
| } |
| } |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| ExtensionFunction::ResponseAction |
| AccessibilityPrivateSetHighlightsFunction::Run() { |
| auto* accessibility_manager = |
| chromecast::shell::CastBrowserProcess::GetInstance() |
| ->accessibility_manager(); |
| |
| std::unique_ptr<accessibility_private::SetHighlights::Params> params( |
| accessibility_private::SetHighlights::Params::Create(args())); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| std::vector<gfx::Rect> rects; |
| for (const accessibility_private::ScreenRect& rect : params->rects) { |
| rects.push_back(gfx::Rect(rect.left, rect.top, rect.width, rect.height)); |
| } |
| |
| SkColor color; |
| if (!extensions::image_util::ParseHexColorString(params->color, &color)) |
| return RespondNow(Error("Could not parse hex color")); |
| |
| // Set the highlights to cover all of these rects. |
| accessibility_manager->SetHighlights(rects, color); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| ExtensionFunction::ResponseAction |
| AccessibilityPrivateSetKeyboardListenerFunction::Run() { |
| LOG(ERROR) << "AccessibilityPrivateSetKeyboardListenerFunction"; |
| return RespondNow(Error(kErrorNotSupported)); |
| } |
| |
| ExtensionFunction::ResponseAction |
| AccessibilityPrivateDarkenScreenFunction::Run() { |
| LOG(ERROR) << "AccessibilityPrivateDarkenScreenFunction"; |
| return RespondNow(Error(kErrorNotSupported)); |
| } |
| |
| ExtensionFunction::ResponseAction |
| AccessibilityPrivateSetNativeChromeVoxArcSupportForCurrentAppFunction::Run() { |
| LOG(ERROR) << "AccessibilityPrivateSetNativeChromeVoxArcSupportForCurrentAppF" |
| "unction"; |
| return RespondNow(Error(kErrorNotSupported)); |
| } |
| |
| ExtensionFunction::ResponseAction |
| AccessibilityPrivateSendSyntheticKeyEventFunction::Run() { |
| LOG(ERROR) << "AccessibilityPrivateSendSyntheticKeyEventFunction"; |
| return RespondNow(Error(kErrorNotSupported)); |
| } |
| |
| ExtensionFunction::ResponseAction |
| AccessibilityPrivateSendSyntheticMouseEventFunction::Run() { |
| std::unique_ptr<accessibility_private::SendSyntheticMouseEvent::Params> |
| params = accessibility_private::SendSyntheticMouseEvent::Params::Create( |
| args()); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| accessibility_private::SyntheticMouseEvent* mouse_data = ¶ms->mouse_event; |
| |
| if (mouse_data->type == |
| accessibility_private::SYNTHETIC_MOUSE_EVENT_TYPE_RELEASE && |
| mouse_data->mouse_button == |
| accessibility_private::SYNTHETIC_MOUSE_EVENT_BUTTON_LEFT) { |
| // ui::ET_TOUCH_PRESSED and ui::ET_TOUCH_RELEASED is sent for synthetic |
| // mouse event left button click. |
| ui::PointerDetails pointer_details; |
| pointer_details.pointer_type = ui::EventPointerType::kTouch; |
| |
| gfx::Point location(mouse_data->x, mouse_data->y); |
| |
| auto* host = chromecast::shell::CastBrowserProcess::GetInstance() |
| ->accessibility_manager() |
| ->window_tree_host(); |
| DCHECK(host); |
| |
| std::unique_ptr<ui::TouchEvent> touch_press = |
| std::make_unique<ui::TouchEvent>(ui::ET_TOUCH_PRESSED, gfx::Point(), |
| ui::EventTimeForNow(), |
| pointer_details); |
| touch_press->set_location(location); |
| touch_press->set_root_location(location); |
| touch_press->UpdateForRootTransform( |
| host->GetRootTransform(), |
| host->GetRootTransformForLocalEventCoordinates()); |
| host->DeliverEventToSink(touch_press.get()); |
| |
| std::unique_ptr<ui::TouchEvent> touch_release = |
| std::make_unique<ui::TouchEvent>(ui::ET_TOUCH_RELEASED, gfx::Point(), |
| ui::EventTimeForNow(), |
| pointer_details); |
| touch_release->set_location(location); |
| touch_release->set_root_location(location); |
| touch_release->UpdateForRootTransform( |
| host->GetRootTransform(), |
| host->GetRootTransformForLocalEventCoordinates()); |
| host->DeliverEventToSink(touch_release.get()); |
| } |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| } // namespace api |
| } // namespace cast |
| } // namespace extensions |