| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |