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
ash / system / accessibility / facegaze_bubble_controller.cc [blame]
// Copyright 2024 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/system/accessibility/facegaze_bubble_controller.h"
#include "ash/system/accessibility/facegaze_bubble_view.h"
#include "ash/wm/collision_detection/collision_detection_utils.h"
#include "base/functional/bind.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
constexpr base::TimeDelta kShowTimeout = base::Seconds(1);
constexpr int kMarginFromTopDip = 8;
} // namespace
FaceGazeBubbleController::FaceGazeBubbleController() = default;
FaceGazeBubbleController::~FaceGazeBubbleController() {
show_timer_.Stop();
if (widget_ && !widget_->IsClosed()) {
widget_->CloseNow();
}
}
void FaceGazeBubbleController::OnViewIsDeleting(views::View* observed_view) {
if (observed_view != facegaze_bubble_view_) {
return;
}
show_timer_.Stop();
facegaze_bubble_view_->views::View::RemoveObserver(this);
facegaze_bubble_view_ = nullptr;
widget_ = nullptr;
}
void FaceGazeBubbleController::UpdateBubble(const std::u16string& text,
bool is_warning) {
MaybeInitialize();
Update(text, is_warning);
if (!show_timer_.IsRunning()) {
widget_->Show();
}
}
void FaceGazeBubbleController::MaybeInitialize() {
if (widget_) {
return;
}
facegaze_bubble_view_ = new FaceGazeBubbleView(base::BindRepeating(
&FaceGazeBubbleController::OnMouseEntered, GetWeakPtr()));
facegaze_bubble_view_->views::View::AddObserver(this);
widget_ =
views::BubbleDialogDelegateView::CreateBubble(facegaze_bubble_view_);
CollisionDetectionUtils::MarkWindowPriorityForCollisionDetection(
widget_->GetNativeWindow(),
CollisionDetectionUtils::RelativePriority::kFaceGazeBubble);
}
void FaceGazeBubbleController::Update(const std::u16string& text,
bool is_warning) {
if (!facegaze_bubble_view_) {
return;
}
facegaze_bubble_view_->Update(text, is_warning);
const gfx::Rect primary_work_area =
display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
const gfx::Size work_area_size = primary_work_area.size();
const gfx::Size bubble_size = facegaze_bubble_view_->size();
// The bubble should be centered at the top of the screen, factoring in other
// UI elements such as the ChromeVox panel. Note that the work area may not
// always start at (0, 0) so we need to factor in the starting point of the
// work area.
int center = (work_area_size.width() / 2) - (bubble_size.width() / 2) +
primary_work_area.x();
int top = primary_work_area.y() + kMarginFromTopDip;
facegaze_bubble_view_->SetAnchorRect(gfx::Rect(center, top, 0, 0));
}
void FaceGazeBubbleController::OnMouseEntered() {
widget_->Hide();
show_timer_.Start(FROM_HERE, kShowTimeout,
base::BindRepeating(&FaceGazeBubbleController::OnShowTimer,
GetWeakPtr()));
}
void FaceGazeBubbleController::OnShowTimer() {
widget_->Show();
}
} // namespace ash