1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/ash/assistant/assistant_context_util.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "chrome/browser/chromeos/profiles/profile_helper.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_list.h"
13 #include "chrome/browser/ui/browser_window.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chromeos/ui/base/window_properties.h"
16 #include "components/arc/arc_service_manager.h"
17 #include "components/arc/mojom/app.mojom.h"
18 #include "components/arc/session/arc_bridge_service.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/web_contents.h"
21 #include "ui/accessibility/ax_assistant_structure.h"
22 #include "ui/aura/window.h"
23 #include "ui/aura/window_tree_host.h"
24 #include "ui/gfx/geometry/point.h"
25 #include "ui/snapshot/snapshot.h"
26 
27 namespace {
28 
CreateAssistantStructureAndRunCallback(RequestAssistantStructureCallback callback,ax::mojom::AssistantExtraPtr assistant_extra,const ui::AXTreeUpdate & update)29 void CreateAssistantStructureAndRunCallback(
30     RequestAssistantStructureCallback callback,
31     ax::mojom::AssistantExtraPtr assistant_extra,
32     const ui::AXTreeUpdate& update) {
33   std::move(callback).Run(std::move(assistant_extra),
34                           ui::CreateAssistantTree(update, false));
35 }
36 
CreateAssistantExtra(content::WebContents * web_contents,const gfx::Rect & bounds_pixel)37 ax::mojom::AssistantExtraPtr CreateAssistantExtra(
38     content::WebContents* web_contents,
39     const gfx::Rect& bounds_pixel) {
40   auto assistant_extra = ax::mojom::AssistantExtra::New();
41   assistant_extra->url = web_contents->GetLastCommittedURL();
42   assistant_extra->title = web_contents->GetTitle();
43   assistant_extra->bounds_pixel = bounds_pixel;
44   return assistant_extra;
45 }
46 
47 }  // namespace
48 
RequestAssistantStructureForActiveBrowserWindow(RequestAssistantStructureCallback callback)49 void RequestAssistantStructureForActiveBrowserWindow(
50     RequestAssistantStructureCallback callback) {
51   Browser* browser = BrowserList::GetInstance()->GetLastActive();
52   if (!browser || !browser->window()->IsActive()) {
53     DCHECK(arc::ArcServiceManager::Get());
54     arc::mojom::AppInstance* app_instance = ARC_GET_INSTANCE_FOR_METHOD(
55         arc::ArcServiceManager::Get()->arc_bridge_service()->app(),
56         RequestAssistStructure);
57     if (!app_instance) {
58       std::move(callback).Run(nullptr, nullptr);
59       return;
60     }
61 
62     app_instance->RequestAssistStructure(std::move(callback));
63     return;
64   }
65 
66   // Only returns context from the profile with assistant, which is primary
67   // profile.
68   if (!chromeos::ProfileHelper::IsPrimaryProfile(browser->profile())) {
69     std::move(callback).Run(nullptr, nullptr);
70     return;
71   }
72 
73   aura::Window* window = browser->window()->GetNativeWindow();
74   // Ignore incognito window.
75   if (window->GetProperty(chromeos::kBlockedForAssistantSnapshotKey)) {
76     std::move(callback).Run(nullptr, nullptr);
77     return;
78   }
79 
80   // We follow same convention as Clank and thus the contents are all in
81   // pixels. The bounds of the window need to be converted to pixel in order
82   // to be consistent with rest of the view hierarchy.
83   gfx::Rect bounds = browser->window()->GetBounds();
84   gfx::Point top_left = bounds.origin();
85   gfx::Point bottom_right = bounds.bottom_right();
86   auto* window_tree_host = window->GetRootWindow()->GetHost();
87   // TODO: Revisit once multi-monitor support is planned.
88   window_tree_host->ConvertDIPToScreenInPixels(&top_left);
89   window_tree_host->ConvertDIPToScreenInPixels(&bottom_right);
90 
91   content::WebContents* web_contents =
92       browser->tab_strip_model()->GetActiveWebContents();
93   web_contents->RequestAXTreeSnapshot(
94       base::BindOnce(
95           &CreateAssistantStructureAndRunCallback, std::move(callback),
96           CreateAssistantExtra(web_contents,
97                                gfx::Rect(top_left.x(), top_left.y(),
98                                          bottom_right.x() - top_left.x(),
99                                          bottom_right.y() - top_left.y()))),
100       ui::kAXModeComplete);
101 }
102 
RequestAssistantStructureForWebContentsForTesting(content::WebContents * web_contents,RequestAssistantStructureCallback callback)103 void RequestAssistantStructureForWebContentsForTesting(
104     content::WebContents* web_contents,
105     RequestAssistantStructureCallback callback) {
106   web_contents->RequestAXTreeSnapshot(
107       base::BindOnce(
108           &CreateAssistantStructureAndRunCallback, std::move(callback),
109           CreateAssistantExtra(web_contents, gfx::Rect(0, 0, 100, 100))),
110       ui::kAXModeComplete);
111 }
112