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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
// 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/annotator/annotator_controller.h"
#include "ash/annotator/annotation_source_watcher.h"
#include "ash/annotator/annotation_tray.h"
#include "ash/annotator/annotations_overlay_controller.h"
#include "ash/annotator/annotator_metrics.h"
#include "ash/capture_mode/capture_mode_controller.h"
#include "ash/projector/projector_metrics.h"
#include "ash/public/cpp/annotator/annotations_overlay_view.h"
#include "ash/public/cpp/annotator/annotator_tool.h"
#include "ash/root_window_controller.h"
#include "ash/system/status_area_widget.h"
#include "ash/webui/annotator/public/cpp/annotator_client.h"
#include "base/check.h"
#include "ui/aura/window.h"
#include "ui/gfx/geometry/rect_f.h"
namespace ash {
namespace {
AnnotatorMarkerColor GetMarkerColorForMetrics(SkColor color) {
switch (color) {
case kAnnotatorMagentaPenColor:
return AnnotatorMarkerColor::kMagenta;
case kAnnotatorBluePenColor:
return AnnotatorMarkerColor::kBlue;
case kAnnotatorRedPenColor:
return AnnotatorMarkerColor::kRed;
case kAnnotatorYellowPenColor:
return AnnotatorMarkerColor::kYellow;
}
return AnnotatorMarkerColor::kMaxValue;
}
AnnotationTray* GetAnnotationTrayForRoot(aura::Window* root) {
// It may happen that root is nullptr. This may happen in the event that
// the annotation tray is hidden before the canvas finishes its
// initialization.
if (!root) {
return nullptr;
}
DCHECK(root->IsRootWindow());
// Annotating can end when a display being fullscreen-captured gets removed,
// in this case, we don't need to hide the button.
if (root->is_destroying()) {
return nullptr;
}
// Can be null while shutting down.
auto* root_window_controller = RootWindowController::ForWindow(root);
if (!root_window_controller) {
return nullptr;
}
auto* annotation_tray =
root_window_controller->GetStatusAreaWidget()->annotation_tray();
DCHECK(annotation_tray);
return annotation_tray;
}
void SetAnnotationTrayVisibility(aura::Window* root, bool visible) {
if (auto* annotation_tray = GetAnnotationTrayForRoot(root)) {
annotation_tray->SetVisiblePreferred(visible);
}
}
} // namespace
AnnotatorController::AnnotatorController() {
annotation_source_watcher_ = std::make_unique<AnnotationSourceWatcher>(this);
UpdateAnnotationTrayAccessibleName(/*is_annotator_enabled=*/true);
}
AnnotatorController::~AnnotatorController() {
annotation_source_watcher_.reset();
annotations_overlay_controller_.reset();
client_ = nullptr;
current_root_ = nullptr;
UpdateAnnotationTrayAccessibleName(/*is_annotator_enabled=*/false);
}
void AnnotatorController::SetAnnotatorTool(const AnnotatorTool& tool) {
DCHECK(client_);
client_->SetTool(tool);
RecordMarkerColorMetrics(GetMarkerColorForMetrics(tool.color));
}
void AnnotatorController::ResetTools() {
if (annotator_enabled_) {
DCHECK(client_);
ToggleAnnotatorCanvas();
annotator_enabled_ = false;
client_->Clear();
UpdateAnnotationTrayAccessibleName(/*is_annotator_enabled=*/false);
}
}
void AnnotatorController::RegisterView(aura::Window* new_root) {
// Make sure the annotator tray is only visible on one root window.
// TODO(b/342104047): Remove this check when annotator starts being used
// outside of the capture mode.
if (current_root_) {
UnregisterView(current_root_);
}
current_root_ = new_root;
// Show the tray icon.
SetAnnotationTrayVisibility(current_root_, /*visible=*/true);
}
void AnnotatorController::UnregisterView(aura::Window* window) {
DCHECK_EQ(current_root_, window);
if (auto* annotation_tray = GetAnnotationTrayForRoot(current_root_)) {
annotation_tray->HideAnnotationTray();
}
current_root_ = nullptr;
}
void AnnotatorController::UpdateRootView(aura::Window* new_root) {
// Do nothing if the root window is the same.
if (new_root == current_root_) {
return;
}
UnregisterView(current_root_);
RegisterView(new_root);
current_root_ = new_root;
if (GetAnnotatorAvailability()) {
UpdateTrayEnabledState();
}
}
void AnnotatorController::EnableAnnotatorTool() {
if (!annotator_enabled_ && annotations_overlay_controller_) {
ToggleAnnotatorCanvas();
annotator_enabled_ = !annotator_enabled_;
UpdateAnnotationTrayAccessibleName(annotator_enabled_);
// TODO(b/342104047): Decouple from projector metrics.
RecordToolbarMetrics(ProjectorToolbar::kMarkerTool);
}
}
void AnnotatorController::DisableAnnotator() {
ResetTools();
if (current_root_) {
UnregisterView(current_root_);
}
annotations_overlay_controller_.reset();
canvas_initialized_state_.reset();
}
void AnnotatorController::CreateAnnotationOverlayForWindow(
aura::Window* window,
std::optional<gfx::Rect> partial_region_bounds) {
annotations_overlay_controller_ =
std::make_unique<AnnotationsOverlayController>(window,
partial_region_bounds);
}
void AnnotatorController::UpdateAnnotationTrayAccessibleName(
bool is_annotator_enabled) {
if (auto* annotation_tray = GetAnnotationTrayForRoot(current_root_)) {
annotation_tray->UpdateAccessibleName(is_annotator_enabled);
}
}
void AnnotatorController::SetToolClient(AnnotatorClient* client) {
client_ = client;
}
bool AnnotatorController::GetAnnotatorAvailability() const {
return canvas_initialized_state_.value_or(false);
}
void AnnotatorController::OnCanvasInitialized(bool success) {
canvas_initialized_state_ = success;
UpdateTrayEnabledState();
if (on_canvas_initialized_callback_for_test_) {
std::move(on_canvas_initialized_callback_for_test_).Run();
}
}
void AnnotatorController::ToggleAnnotationTray() {
if (auto* annotation_tray = GetAnnotationTrayForRoot(current_root_)) {
annotation_tray->ToggleAnnotator();
}
}
// Callback indicating availability of undo and redo functionalities.
void AnnotatorController::OnUndoRedoAvailabilityChanged(bool undo_available,
bool redo_available) {
// TODO(b/198184362): Reflect undo and redo buttons availability
// on the annotator tray.
}
std::unique_ptr<AnnotationsOverlayView>
AnnotatorController::CreateAnnotationsOverlayView() const {
return client_->CreateAnnotationsOverlayView();
}
void AnnotatorController::UpdateTrayEnabledState() {
if (auto* annotation_tray = GetAnnotationTrayForRoot(current_root_)) {
annotation_tray->SetTrayEnabled(GetAnnotatorAvailability());
}
}
void AnnotatorController::ToggleAnnotatorCanvas() {
auto* capture_mode_controller = CaptureModeController::Get();
// TODO(b/342104047): This check is necessary as long as we only toggle
// annotator from Projector. Once we start using the annotator outside of
// Projector, we should remove the check.
if (capture_mode_controller->is_recording_in_progress()) {
annotations_overlay_controller_->Toggle();
}
}
} // namespace ash
|