Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(911)

Side by Side Diff: chrome/browser/extensions/api/automation_internal/automation_internal_api.cc

Issue 2700103004: Initial support for accessibility actions on ARC. (Closed)
Patch Set: Rename cleanup. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/automation_internal/automation_internal_ api.h" 5 #include "chrome/browser/extensions/api/automation_internal/automation_internal_ api.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/macros.h" 11 #include "base/macros.h"
12 #include "base/memory/ptr_util.h" 12 #include "base/memory/ptr_util.h"
13 #include "base/strings/string16.h" 13 #include "base/strings/string16.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/extensions/api/automation_internal/automation_action_ad apter.h"
17 #include "chrome/browser/extensions/api/automation_internal/automation_event_rou ter.h" 16 #include "chrome/browser/extensions/api/automation_internal/automation_event_rou ter.h"
18 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" 17 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
19 #include "chrome/browser/extensions/extension_tab_util.h" 18 #include "chrome/browser/extensions/extension_tab_util.h"
20 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/ui/browser.h" 20 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model.h" 21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
23 #include "chrome/common/extensions/api/automation_api_constants.h" 22 #include "chrome/common/extensions/api/automation_api_constants.h"
24 #include "chrome/common/extensions/api/automation_internal.h" 23 #include "chrome/common/extensions/api/automation_internal.h"
25 #include "chrome/common/extensions/chrome_extension_messages.h" 24 #include "chrome/common/extensions/chrome_extension_messages.h"
26 #include "chrome/common/extensions/manifest_handlers/automation.h" 25 #include "chrome/common/extensions/manifest_handlers/automation.h"
27 #include "content/public/browser/ax_event_notification_details.h" 26 #include "content/public/browser/ax_event_notification_details.h"
28 #include "content/public/browser/browser_accessibility_state.h" 27 #include "content/public/browser/browser_accessibility_state.h"
29 #include "content/public/browser/browser_context.h" 28 #include "content/public/browser/browser_context.h"
30 #include "content/public/browser/browser_plugin_guest_manager.h" 29 #include "content/public/browser/browser_plugin_guest_manager.h"
31 #include "content/public/browser/media_session.h" 30 #include "content/public/browser/media_session.h"
32 #include "content/public/browser/render_frame_host.h" 31 #include "content/public/browser/render_frame_host.h"
33 #include "content/public/browser/render_view_host.h" 32 #include "content/public/browser/render_view_host.h"
34 #include "content/public/browser/render_widget_host.h" 33 #include "content/public/browser/render_widget_host.h"
35 #include "content/public/browser/render_widget_host_view.h" 34 #include "content/public/browser/render_widget_host_view.h"
36 #include "content/public/browser/web_contents.h" 35 #include "content/public/browser/web_contents.h"
37 #include "content/public/browser/web_contents_observer.h" 36 #include "content/public/browser/web_contents_observer.h"
38 #include "content/public/browser/web_contents_user_data.h" 37 #include "content/public/browser/web_contents_user_data.h"
39 #include "extensions/common/extension_messages.h" 38 #include "extensions/common/extension_messages.h"
40 #include "extensions/common/permissions/permissions_data.h" 39 #include "extensions/common/permissions/permissions_data.h"
41 #include "ui/accessibility/ax_action_data.h" 40 #include "ui/accessibility/ax_action_data.h"
41 #include "ui/accessibility/ax_host_delegate.h"
42 #include "ui/accessibility/ax_tree_id_registry.h"
42 43
43 #if defined(USE_AURA) 44 #if defined(USE_AURA)
44 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h" 45 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
45 #endif 46 #endif
46 47
47 namespace extensions { 48 namespace extensions {
48 class AutomationWebContentsObserver; 49 class AutomationWebContentsObserver;
49 } // namespace extensions 50 } // namespace extensions
50 51
51 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::AutomationWebContentsObserver); 52 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::AutomationWebContentsObserver);
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 // TODO(aboxhall): check for webstore URL 149 // TODO(aboxhall): check for webstore URL
149 if (automation_info->matches.MatchesURL(url)) 150 if (automation_info->matches.MatchesURL(url))
150 return true; 151 return true;
151 152
152 int tab_id = ExtensionTabUtil::GetTabId(contents); 153 int tab_id = ExtensionTabUtil::GetTabId(contents);
153 std::string unused_error; 154 std::string unused_error;
154 return extension->permissions_data()->CanAccessPage(extension, url, tab_id, 155 return extension->permissions_data()->CanAccessPage(extension, url, tab_id,
155 &unused_error); 156 &unused_error);
156 } 157 }
157 158
158 // Helper class that implements an action adapter for a |RenderFrameHost|.
159 class RenderFrameHostActionAdapter : public AutomationActionAdapter {
160 public:
161 explicit RenderFrameHostActionAdapter(content::RenderFrameHost* rfh)
162 : rfh_(rfh) {}
163
164 virtual ~RenderFrameHostActionAdapter() {}
165
166 // AutomationActionAdapter implementation.
167 void PerformAction(const ui::AXActionData& data) override {
168 rfh_->AccessibilityPerformAction(data);
169 }
170
171 private:
172 content::RenderFrameHost* rfh_;
173
174 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostActionAdapter);
175 };
176
177 } // namespace 159 } // namespace
178 160
179 // Helper class that receives accessibility data from |WebContents|. 161 // Helper class that receives accessibility data from |WebContents|.
180 class AutomationWebContentsObserver 162 class AutomationWebContentsObserver
181 : public content::WebContentsObserver, 163 : public content::WebContentsObserver,
182 public content::WebContentsUserData<AutomationWebContentsObserver> { 164 public content::WebContentsUserData<AutomationWebContentsObserver> {
183 public: 165 public:
184 ~AutomationWebContentsObserver() override {} 166 ~AutomationWebContentsObserver() override {}
185 167
186 // content::WebContentsObserver overrides. 168 // content::WebContentsObserver overrides.
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 320
339 // Only call this if this is the root of a frame tree, to avoid resetting 321 // Only call this if this is the root of a frame tree, to avoid resetting
340 // the accessibility state multiple times. 322 // the accessibility state multiple times.
341 if (!rfh->GetParent()) 323 if (!rfh->GetParent())
342 contents->EnableWebContentsOnlyAccessibilityMode(); 324 contents->EnableWebContentsOnlyAccessibilityMode();
343 325
344 return RespondNow(NoArguments()); 326 return RespondNow(NoArguments());
345 } 327 }
346 328
347 ExtensionFunction::ResponseAction 329 ExtensionFunction::ResponseAction
330 AutomationInternalPerformActionFunction::ConvertToAXActionData(
331 api::automation_internal::PerformAction::Params* params,
332 ui::AXActionData* action) {
333 action->target_node_id = params->args.automation_node_id;
334 switch (params->args.action_type) {
335 case api::automation_internal::ACTION_TYPE_DODEFAULT:
336 action->action = ui::AX_ACTION_DO_DEFAULT;
337 break;
338 case api::automation_internal::ACTION_TYPE_FOCUS:
339 action->action = ui::AX_ACTION_FOCUS;
340 break;
341 case api::automation_internal::ACTION_TYPE_GETIMAGEDATA: {
342 api::automation_internal::GetImageDataParams get_image_data_params;
343 EXTENSION_FUNCTION_VALIDATE(
344 api::automation_internal::GetImageDataParams::Populate(
345 params->opt_args.additional_properties, &get_image_data_params));
346 action->action = ui::AX_ACTION_GET_IMAGE_DATA;
347 action->target_rect = gfx::Rect(0, 0, get_image_data_params.max_width,
348 get_image_data_params.max_height);
349 break;
350 }
351 case api::automation_internal::ACTION_TYPE_MAKEVISIBLE:
352 action->action = ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE;
353 break;
354 case api::automation_internal::ACTION_TYPE_SETSELECTION: {
355 api::automation_internal::SetSelectionParams selection_params;
356 EXTENSION_FUNCTION_VALIDATE(
357 api::automation_internal::SetSelectionParams::Populate(
358 params->opt_args.additional_properties, &selection_params));
359 action->anchor_node_id = params->args.automation_node_id;
360 action->anchor_offset = selection_params.anchor_offset;
361 action->focus_node_id = selection_params.focus_node_id;
362 action->focus_offset = selection_params.focus_offset;
363 action->action = ui::AX_ACTION_SET_SELECTION;
364 break;
365 }
366 case api::automation_internal::ACTION_TYPE_SHOWCONTEXTMENU: {
367 action->action = ui::AX_ACTION_SHOW_CONTEXT_MENU;
368 break;
369 }
370 case api::automation_internal::ACTION_TYPE_SETACCESSIBILITYFOCUS: {
371 action->action = ui::AX_ACTION_SET_ACCESSIBILITY_FOCUS;
372 break;
373 }
374 case api::automation_internal::
375 ACTION_TYPE_SETSEQUENTIALFOCUSNAVIGATIONSTARTINGPOINT: {
376 action->action =
377 ui::AX_ACTION_SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT;
378 break;
379 }
380 default:
381 NOTREACHED();
382 }
383 return RespondNow(NoArguments());
384 }
385
386 ExtensionFunction::ResponseAction
348 AutomationInternalPerformActionFunction::Run() { 387 AutomationInternalPerformActionFunction::Run() {
349 const AutomationInfo* automation_info = AutomationInfo::Get(extension()); 388 const AutomationInfo* automation_info = AutomationInfo::Get(extension());
350 EXTENSION_FUNCTION_VALIDATE(automation_info && automation_info->interact); 389 EXTENSION_FUNCTION_VALIDATE(automation_info && automation_info->interact);
351 390
352 using api::automation_internal::PerformAction::Params; 391 using api::automation_internal::PerformAction::Params;
353 std::unique_ptr<Params> params(Params::Create(*args_)); 392 std::unique_ptr<Params> params(Params::Create(*args_));
354 EXTENSION_FUNCTION_VALIDATE(params.get()); 393 EXTENSION_FUNCTION_VALIDATE(params.get());
355 394 ui::AXTreeIDRegistry* registry = ui::AXTreeIDRegistry::GetInstance();
356 if (params->args.tree_id == api::automation::kDesktopTreeID) { 395 ui::AXHostDelegate* delegate =
396 registry->GetHostDelegate(params->args.tree_id);
397 if (delegate) {
357 #if defined(USE_AURA) 398 #if defined(USE_AURA)
358 return RouteActionToAdapter(params.get(), 399 ui::AXActionData data;
359 AutomationManagerAura::GetInstance()); 400 ConvertToAXActionData(params.get(), &data);
401 delegate->PerformAction(data);
360 #else 402 #else
361 NOTREACHED(); 403 NOTREACHED();
362 return RespondNow(Error("Unexpected action on desktop automation tree;" 404 return RespondNow(Error("Unexpected action on desktop automation tree;"
363 " platform does not support desktop automation")); 405 " platform does not support desktop automation"));
364 #endif // defined(USE_AURA) 406 #endif // defined(USE_AURA)
365 } 407 }
366 content::RenderFrameHost* rfh = 408 content::RenderFrameHost* rfh =
367 content::RenderFrameHost::FromAXTreeID(params->args.tree_id); 409 content::RenderFrameHost::FromAXTreeID(params->args.tree_id);
368 if (!rfh) 410 if (!rfh)
369 return RespondNow(Error("Ignoring action on destroyed node")); 411 return RespondNow(Error("Ignoring action on destroyed node"));
(...skipping 20 matching lines...) Expand all
390 api::automation_internal::ACTION_TYPE_RESUMEMEDIA) { 432 api::automation_internal::ACTION_TYPE_RESUMEMEDIA) {
391 content::MediaSession* session = content::MediaSession::Get(contents); 433 content::MediaSession* session = content::MediaSession::Get(contents);
392 session->Resume(content::MediaSession::SuspendType::SYSTEM); 434 session->Resume(content::MediaSession::SuspendType::SYSTEM);
393 return RespondNow(NoArguments()); 435 return RespondNow(NoArguments());
394 } else if (params->args.action_type == 436 } else if (params->args.action_type ==
395 api::automation_internal::ACTION_TYPE_SUSPENDMEDIA) { 437 api::automation_internal::ACTION_TYPE_SUSPENDMEDIA) {
396 content::MediaSession* session = content::MediaSession::Get(contents); 438 content::MediaSession* session = content::MediaSession::Get(contents);
397 session->Suspend(content::MediaSession::SuspendType::SYSTEM); 439 session->Suspend(content::MediaSession::SuspendType::SYSTEM);
398 return RespondNow(NoArguments()); 440 return RespondNow(NoArguments());
399 } 441 }
400 442 ui::AXActionData data;
401 RenderFrameHostActionAdapter adapter(rfh); 443 ExtensionFunction::ResponseAction result =
402 return RouteActionToAdapter(params.get(), &adapter); 444 ConvertToAXActionData(params.get(), &data);
445 rfh->AccessibilityPerformAction(data);
446 return result;
403 } 447 }
404 448
405 ExtensionFunction::ResponseAction 449 ExtensionFunction::ResponseAction
406 AutomationInternalPerformActionFunction::RouteActionToAdapter(
407 api::automation_internal::PerformAction::Params* params,
408 AutomationActionAdapter* adapter) {
409 ui::AXActionData action;
410 action.target_node_id = params->args.automation_node_id;
411 switch (params->args.action_type) {
412 case api::automation_internal::ACTION_TYPE_DODEFAULT:
413 action.action = ui::AX_ACTION_DO_DEFAULT;
414 adapter->PerformAction(action);
415 break;
416 case api::automation_internal::ACTION_TYPE_FOCUS:
417 action.action = ui::AX_ACTION_FOCUS;
418 adapter->PerformAction(action);
419 break;
420 case api::automation_internal::ACTION_TYPE_GETIMAGEDATA: {
421 api::automation_internal::GetImageDataParams get_image_data_params;
422 EXTENSION_FUNCTION_VALIDATE(
423 api::automation_internal::GetImageDataParams::Populate(
424 params->opt_args.additional_properties, &get_image_data_params));
425 action.action = ui::AX_ACTION_GET_IMAGE_DATA;
426 action.target_rect = gfx::Rect(
427 0, 0, get_image_data_params.max_width,
428 get_image_data_params.max_height);
429 adapter->PerformAction(action);
430 break;
431 }
432 case api::automation_internal::ACTION_TYPE_MAKEVISIBLE:
433 action.action = ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE;
434 adapter->PerformAction(action);
435 break;
436 case api::automation_internal::ACTION_TYPE_SETSELECTION: {
437 api::automation_internal::SetSelectionParams selection_params;
438 EXTENSION_FUNCTION_VALIDATE(
439 api::automation_internal::SetSelectionParams::Populate(
440 params->opt_args.additional_properties, &selection_params));
441 action.anchor_node_id = params->args.automation_node_id;
442 action.anchor_offset = selection_params.anchor_offset;
443 action.focus_node_id = selection_params.focus_node_id;
444 action.focus_offset = selection_params.focus_offset;
445 action.action = ui::AX_ACTION_SET_SELECTION;
446 adapter->PerformAction(action);
447 break;
448 }
449 case api::automation_internal::ACTION_TYPE_SHOWCONTEXTMENU: {
450 action.action = ui::AX_ACTION_SHOW_CONTEXT_MENU;
451 adapter->PerformAction(action);
452 break;
453 }
454 case api::automation_internal::ACTION_TYPE_SETACCESSIBILITYFOCUS: {
455 action.action = ui::AX_ACTION_SET_ACCESSIBILITY_FOCUS;
456 adapter->PerformAction(action);
457 break;
458 }
459 case api::automation_internal::
460 ACTION_TYPE_SETSEQUENTIALFOCUSNAVIGATIONSTARTINGPOINT: {
461 action.action =
462 ui::AX_ACTION_SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT;
463 adapter->PerformAction(action);
464 break;
465 }
466 default:
467 NOTREACHED();
468 }
469 return RespondNow(NoArguments());
470 }
471
472 ExtensionFunction::ResponseAction
473 AutomationInternalEnableDesktopFunction::Run() { 450 AutomationInternalEnableDesktopFunction::Run() {
474 #if defined(USE_AURA) 451 #if defined(USE_AURA)
475 const AutomationInfo* automation_info = AutomationInfo::Get(extension()); 452 const AutomationInfo* automation_info = AutomationInfo::Get(extension());
476 if (!automation_info || !automation_info->desktop) 453 if (!automation_info || !automation_info->desktop)
477 return RespondNow(Error("desktop permission must be requested")); 454 return RespondNow(Error("desktop permission must be requested"));
478 455
479 using api::automation_internal::EnableDesktop::Params; 456 using api::automation_internal::EnableDesktop::Params;
480 std::unique_ptr<Params> params(Params::Create(*args_)); 457 std::unique_ptr<Params> params(Params::Create(*args_));
481 EXTENSION_FUNCTION_VALIDATE(params.get()); 458 EXTENSION_FUNCTION_VALIDATE(params.get());
482 459
(...skipping 15 matching lines...) Expand all
498 475
499 ExtensionFunction::ResponseAction 476 ExtensionFunction::ResponseAction
500 AutomationInternalQuerySelectorFunction::Run() { 477 AutomationInternalQuerySelectorFunction::Run() {
501 const AutomationInfo* automation_info = AutomationInfo::Get(extension()); 478 const AutomationInfo* automation_info = AutomationInfo::Get(extension());
502 EXTENSION_FUNCTION_VALIDATE(automation_info); 479 EXTENSION_FUNCTION_VALIDATE(automation_info);
503 480
504 using api::automation_internal::QuerySelector::Params; 481 using api::automation_internal::QuerySelector::Params;
505 std::unique_ptr<Params> params(Params::Create(*args_)); 482 std::unique_ptr<Params> params(Params::Create(*args_));
506 EXTENSION_FUNCTION_VALIDATE(params.get()); 483 EXTENSION_FUNCTION_VALIDATE(params.get());
507 484
508 if (params->args.tree_id == api::automation::kDesktopTreeID) {
509 return RespondNow(
510 Error("domQuerySelector queries may not be used on the desktop."));
511 }
512 content::RenderFrameHost* rfh = 485 content::RenderFrameHost* rfh =
513 content::RenderFrameHost::FromAXTreeID(params->args.tree_id); 486 content::RenderFrameHost::FromAXTreeID(params->args.tree_id);
514 if (!rfh) 487 if (!rfh) {
515 return RespondNow(Error("domQuerySelector query sent on destroyed tree.")); 488 return RespondNow(
489 Error("domQuerySelector query sent on non-web or destroyed tree."));
490 }
516 491
517 content::WebContents* contents = 492 content::WebContents* contents =
518 content::WebContents::FromRenderFrameHost(rfh); 493 content::WebContents::FromRenderFrameHost(rfh);
519 494
520 int request_id = query_request_id_counter_++; 495 int request_id = query_request_id_counter_++;
521 base::string16 selector = base::UTF8ToUTF16(params->args.selector); 496 base::string16 selector = base::UTF8ToUTF16(params->args.selector);
522 497
523 // QuerySelectorHandler handles IPCs and deletes itself on completion. 498 // QuerySelectorHandler handles IPCs and deletes itself on completion.
524 new QuerySelectorHandler( 499 new QuerySelectorHandler(
525 contents, request_id, params->args.automation_node_id, selector, 500 contents, request_id, params->args.automation_node_id, selector,
526 base::Bind(&AutomationInternalQuerySelectorFunction::OnResponse, this)); 501 base::Bind(&AutomationInternalQuerySelectorFunction::OnResponse, this));
527 502
528 return RespondLater(); 503 return RespondLater();
529 } 504 }
530 505
531 void AutomationInternalQuerySelectorFunction::OnResponse( 506 void AutomationInternalQuerySelectorFunction::OnResponse(
532 const std::string& error, 507 const std::string& error,
533 int result_acc_obj_id) { 508 int result_acc_obj_id) {
534 if (!error.empty()) { 509 if (!error.empty()) {
535 Respond(Error(error)); 510 Respond(Error(error));
536 return; 511 return;
537 } 512 }
538 513
539 Respond( 514 Respond(
540 OneArgument(base::MakeUnique<base::FundamentalValue>(result_acc_obj_id))); 515 OneArgument(base::MakeUnique<base::FundamentalValue>(result_acc_obj_id)));
541 } 516 }
542 517
543 } // namespace extensions 518 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698