1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
ash / components / arc / touch_selection_menu / touch_selection_menu_runner_chromeos.cc [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/components/arc/touch_selection_menu/touch_selection_menu_runner_chromeos.h"
#include <utility>
#include "ash/components/arc/session/arc_bridge_service.h"
#include "ash/components/arc/session/arc_service_manager.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "base/functional/bind.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/strings/utf_string_conversions.h"
#include "ash/components/arc/touch_selection_menu/touch_selection_menu_chromeos.h"
#include "components/session_manager/session_manager_types.h"
#include "ui/aura/window.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
TouchSelectionMenuRunnerChromeOS::TouchSelectionMenuRunnerChromeOS() = default;
TouchSelectionMenuRunnerChromeOS::~TouchSelectionMenuRunnerChromeOS() = default;
void TouchSelectionMenuRunnerChromeOS::OpenMenuWithTextSelectionAction(
base::WeakPtr<ui::TouchSelectionMenuClient> client,
const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size,
std::unique_ptr<aura::WindowTracker> tracker,
std::vector<arc::mojom::TextSelectionActionPtr> actions) {
if (tracker->windows().empty())
return;
// The `client` may have been deleted during the mojo call to ARC.
if (!client)
return;
if (!client->ShouldShowQuickMenu())
return;
arc::mojom::TextSelectionActionPtr top_action;
// Get the first action generated by the Android TextClassifier.
for (auto& action : actions) {
if (!action->text_classifier_action)
continue;
std::swap(top_action, action);
break;
}
// The menu manages its own lifetime and deletes itself when closed.
TouchSelectionMenuChromeOS* menu = new TouchSelectionMenuChromeOS(
this, client, tracker->Pop(), std::move(top_action));
ShowMenu(menu, anchor_rect, handle_image_size);
}
bool TouchSelectionMenuRunnerChromeOS::RequestTextSelection(
base::WeakPtr<ui::TouchSelectionMenuClient> client,
const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size,
aura::Window* context) {
DCHECK(client);
const std::string converted_text =
base::UTF16ToUTF8(client->GetSelectedText());
if (converted_text.empty())
return false;
// Some options like 'Cut' and 'Copy' can be accessed even during login
// screen, however ARC shouldn't be able to starts apps during that state.
const ash::SessionControllerImpl* controller =
ash::Shell::Get()->session_controller();
if (controller->IsScreenLocked() ||
controller->GetSessionState() != session_manager::SessionState::ACTIVE) {
return false;
}
auto* arc_service_manager = arc::ArcServiceManager::Get();
if (!arc_service_manager)
return false;
arc::mojom::IntentHelperInstance* instance = ARC_GET_INSTANCE_FOR_METHOD(
arc_service_manager->arc_bridge_service()->intent_helper(),
RequestTextSelectionActions);
if (!instance)
return false;
// aura::WindowTracker is used since the newly created menu may need to know
// about the parent window.
std::unique_ptr<aura::WindowTracker> tracker =
std::make_unique<aura::WindowTracker>();
tracker->Add(context);
const display::Screen* screen = display::Screen::GetScreen();
DCHECK(screen);
base::RecordAction(base::UserMetricsAction("Arc.SmartTextSelection.Request"));
// Fetch actions for selected text and then show quick menu.
instance->RequestTextSelectionActions(
converted_text,
arc::mojom::ScaleFactor(
screen->GetDisplayNearestWindow(context).device_scale_factor()),
base::BindOnce(
&TouchSelectionMenuRunnerChromeOS::OpenMenuWithTextSelectionAction,
weak_ptr_factory_.GetWeakPtr(), client, anchor_rect,
handle_image_size, std::move(tracker)));
return true;
}
void TouchSelectionMenuRunnerChromeOS::OpenMenu(
base::WeakPtr<ui::TouchSelectionMenuClient> client,
const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size,
aura::Window* context) {
views::TouchSelectionMenuRunnerViews::CloseMenu();
// If there are no commands to show in the menu finish right away. Also if
// classification is possible delegate creating/showing a new menu.
if (!views::TouchSelectionMenuRunnerViews::IsMenuAvailable(client.get()) ||
RequestTextSelection(client, anchor_rect, handle_image_size, context)) {
return;
}
// The menu manages its own lifetime and deletes itself when closed.
TouchSelectionMenuChromeOS* menu =
new TouchSelectionMenuChromeOS(this, client, context,
/*action=*/nullptr);
ShowMenu(menu, anchor_rect, handle_image_size);
}