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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
ash / clipboard / clipboard_history_controller_impl.h [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_CLIPBOARD_CLIPBOARD_HISTORY_CONTROLLER_IMPL_H_
#define ASH_CLIPBOARD_CLIPBOARD_HISTORY_CONTROLLER_IMPL_H_
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "ash/ash_export.h"
#include "ash/clipboard/clipboard_history.h"
#include "ash/clipboard/clipboard_history_resource_manager.h"
#include "ash/public/cpp/clipboard_history_controller.h"
#include "ash/public/cpp/session/session_observer.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/one_shot_event.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "base/values.h"
#include "chromeos/crosapi/mojom/clipboard_history.mojom.h"
#include "ui/base/mojom/menu_source_type.mojom-forward.h"
class PrefRegistrySimple;
namespace aura {
class Window;
} // namespace aura
namespace gfx {
class Rect;
} // namespace gfx
namespace ash {
class ClipboardHistoryControllerDelegate;
class ClipboardHistoryItem;
class ClipboardHistoryMenuModelAdapter;
class ClipboardHistoryResourceManager;
class ClipboardHistoryUrlTitleFetcher;
class ClipboardImageModelFactory;
class ClipboardNudgeController;
class ScopedClipboardHistoryPause;
enum class LoginStatus;
// Shows a menu with the last few things saved in the clipboard when the
// keyboard shortcut is pressed.
class ASH_EXPORT ClipboardHistoryControllerImpl
: public ClipboardHistoryController,
public ClipboardHistory::Observer,
public ClipboardHistoryResourceManager::Observer,
public SessionObserver {
public:
// Source and plain vs. rich text info for each paste. These values are used
// in the Ash.ClipboardHistory.PasteType histogram and therefore cannot be
// reordered. New types may be appended to the end of this enumeration.
enum class ClipboardHistoryPasteType {
kPlainTextAccelerator = 0, // Plain text paste triggered by accelerator
kRichTextAccelerator = 1, // Rich text paste triggered by accelerator
kPlainTextKeystroke = 2, // Plain text paste triggered by keystroke
kRichTextKeystroke = 3, // Rich text paste triggered by keystroke
kPlainTextMouse = 4, // Plain text paste triggered by mouse click
kRichTextMouse = 5, // Rich text paste triggered by mouse click
kPlainTextTouch = 6, // Plain text paste triggered by gesture tap
kRichTextTouch = 7, // Rich text paste triggered by gesture tap
kPlainTextVirtualKeyboard = 8, // Plain text paste triggered by VK request
kRichTextVirtualKeyboard = 9, // Rich text paste triggered by VK request
kPlainTextCtrlV = 10, // Plain text paste triggered by Ctrl+V
kRichTextCtrlV = 11, // Rich text paste triggered by Ctrl+V
kMaxValue = 11
};
explicit ClipboardHistoryControllerImpl(
std::unique_ptr<ClipboardHistoryControllerDelegate> delegate);
ClipboardHistoryControllerImpl(const ClipboardHistoryControllerImpl&) =
delete;
ClipboardHistoryControllerImpl& operator=(
const ClipboardHistoryControllerImpl&) = delete;
~ClipboardHistoryControllerImpl() override;
// Registers clipboard history profile prefs with the specified `registry`.
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
// Clean up the child widgets prior to destruction.
void Shutdown();
// Returns if the contextual menu is currently showing.
bool IsMenuShowing() const;
// Shows or hides the clipboard history menu through the keyboard accelerator.
// If the menu was already shown, pastes the selected menu item before hiding.
// If the menu was not already shown and `is_plain_text_paste` is true the
// menu will not be shown. The common case for `is_plain_text_paste` is to
// allow pasting plain text when menu is already open, otherwise do not allow
// the plain text shortcut to open the menu.
void ToggleMenuShownByAccelerator(bool is_plain_text_paste);
// ClipboardHistoryController:
void AddObserver(ClipboardHistoryController::Observer* observer) override;
void RemoveObserver(ClipboardHistoryController::Observer* observer) override;
bool ShowMenu(const gfx::Rect& anchor_rect,
ui::mojom::MenuSourceType source_type,
crosapi::mojom::ClipboardHistoryControllerShowSource
show_source) override;
bool ShowMenu(
const gfx::Rect& anchor_rect,
ui::mojom::MenuSourceType source_type,
crosapi::mojom::ClipboardHistoryControllerShowSource show_source,
OnMenuClosingCallback callback) override;
void GetHistoryValues(GetHistoryValuesCallback callback) const override;
// Whether the clipboard history has items.
bool IsEmpty() const;
// Fires the timer to notify observers of item updates immediately.
void FireItemUpdateNotificationTimerForTest();
// Returns bounds for the contextual menu in screen coordinates.
gfx::Rect GetMenuBoundsInScreenForTest() const;
// Used to delay the post-encoding step of `GetHistoryValues()` until the
// completion of some work that needs to happen after history values have been
// requested and before the values are returned.
void BlockGetHistoryValuesForTest();
void ResumeGetHistoryValuesForTest();
// Returns the history which tracks what is being copied to the clipboard.
const ClipboardHistory* history() const { return clipboard_history_.get(); }
// Returns the resource manager which gets labels and images for items copied
// to the clipboard.
const ClipboardHistoryResourceManager* resource_manager() const {
return resource_manager_.get();
}
ClipboardNudgeController* nudge_controller() const {
return nudge_controller_.get();
}
ClipboardHistoryMenuModelAdapter* context_menu_for_test() {
return context_menu_.get();
}
void set_buffer_restoration_delay_for_test(
std::optional<base::TimeDelta> delay) {
buffer_restoration_delay_for_test_ = delay;
}
void set_initial_item_selected_callback_for_test(
base::RepeatingClosure new_callback) {
initial_item_selected_callback_for_test_ = new_callback;
}
void set_confirmed_operation_callback_for_test(
base::RepeatingCallback<void(bool)> new_callback) {
confirmed_operation_callback_for_test_ = new_callback;
}
void set_new_bitmap_to_write_while_encoding_for_test(const SkBitmap& bitmap) {
new_bitmap_to_write_while_encoding_for_test_ = bitmap;
}
private:
class AcceleratorTarget;
class MenuDelegate;
// ClipboardHistoryController:
bool HasAvailableHistoryItems() const override;
void OnScreenshotNotificationCreated() override;
std::unique_ptr<ScopedClipboardHistoryPause> CreateScopedPause() override;
std::vector<std::string> GetHistoryItemIds() const override;
bool PasteClipboardItemById(
const std::string& item_id,
int event_flags,
crosapi::mojom::ClipboardHistoryControllerShowSource paste_source)
override;
bool DeleteClipboardItemById(const std::string& item_id) override;
// ClipboardHistory::Observer:
void OnClipboardHistoryItemAdded(const ClipboardHistoryItem& item,
bool is_duplicate) override;
void OnClipboardHistoryItemRemoved(const ClipboardHistoryItem& item) override;
void OnClipboardHistoryCleared() override;
void OnOperationConfirmed(bool copy) override;
// ClipboardHistoryResourceManager:
void OnCachedImageModelUpdated(
const std::vector<base::UnguessableToken>& menu_item_ids) override;
// SessionObserver:
void OnSessionStateChanged(session_manager::SessionState state) override;
void OnLoginStatusChanged(LoginStatus login_status) override;
// Posts a task to notify `observers_` of updates to clipboard history items.
void PostItemUpdateNotificationTask();
// Notifies `observers_` of updates to clipboard history items. No-op if
// there are no available clipboard history items and there were no available
// history items in the last notification.
void MaybeNotifyObserversOfItemUpdate();
// Invoked by `GetHistoryValues()` once all clipboard instances with images
// have been encoded into PNGs. Calls `callback` with the clipboard history
// list, which tracks what has been copied to the clipboard. If clipboard
// history is disabled in the current mode, `callback` will be called with an
// empty history list.
void GetHistoryValuesWithEncodedPNGs(
GetHistoryValuesCallback callback,
std::unique_ptr<std::map<base::UnguessableToken, std::vector<uint8_t>>>
encoded_pngs);
// Executes the command specified by `command_id` with the given
// `event_flags`.
void ExecuteCommand(int command_id, int event_flags);
// Pastes the clipboard data of the clipboard history context menu item
// specified by `command_id`. NOTE: This function assumes that the clipboard
// history context menu has been open. It is different from
// `PasteClipboardItemById()` that can be called without showing the clipboard
// history context menu.
void PasteClipboardItemByCommandId(int command_id,
ClipboardHistoryPasteType paste_type);
// Posts a task to paste `item` with `paste_type` to the active window, if
// any.
void MaybePostPasteTask(
const ClipboardHistoryItem& item,
ClipboardHistoryPasteType paste_type,
crosapi::mojom::ClipboardHistoryControllerShowSource paste_source);
// Pastes the specified clipboard history item, if `intended_window` matches
// the active window. `paste_type` indicates the mode of paste execution for
// metrics tracking as well as whether plain text should be pasted instead of
// the full, rich-text clipboard data. `paste_source` indicates how the user
// triggered the menu from which `item` was selected.
void PasteClipboardHistoryItem(
aura::Window* intended_window,
ClipboardHistoryItem item,
ClipboardHistoryPasteType paste_type,
crosapi::mojom::ClipboardHistoryControllerShowSource paste_source);
// Delete the menu item being selected and its corresponding data. If no item
// is selected, do nothing.
void DeleteSelectedMenuItemIfAny();
// Delete the menu item specified by `command_id` and its corresponding data.
void DeleteItemWithCommandId(int command_id);
// Deletes the specified clipboard history item.
void DeleteClipboardHistoryItem(const ClipboardHistoryItem& item);
// Advances the pseudo focus (backward if `reverse` is true).
void AdvancePseudoFocus(bool reverse);
// Calculates the anchor rect for the ClipboardHistory menu.
gfx::Rect CalculateAnchorRect() const;
// Called when the contextual menu is closed.
void OnMenuClosed();
// Either the browser-implemented or test-implemented delegate depending on
// whether we are running in an Ash-only test context.
const std::unique_ptr<ClipboardHistoryControllerDelegate> delegate_;
// The browser-implemented image model factory that renders html. This will be
// `nullptr` if and only if we are running in an Ash-only test context.
const std::unique_ptr<ClipboardImageModelFactory> image_model_factory_;
// The browser-implemented URL title fetcher. This will be `nullptr` if and
// only if we are running in an Ash-only test context.
const std::unique_ptr<ClipboardHistoryUrlTitleFetcher> url_title_fetcher_;
// Observers notified when clipboard history is shown, used, or updated.
base::ObserverList<ClipboardHistoryController::Observer> observers_;
// Used to keep track of what is being copied to the clipboard.
std::unique_ptr<ClipboardHistory> clipboard_history_;
// Manages resources for clipboard history.
std::unique_ptr<ClipboardHistoryResourceManager> resource_manager_;
// Detects the search+v key combo.
std::unique_ptr<AcceleratorTarget> accelerator_target_;
// Controller that shows contextual nudges for multipaste.
std::unique_ptr<ClipboardNudgeController> nudge_controller_;
// Context menu displayed by `ShowMenu()`. Null when `MenuIsShowing()` is
// false.
std::unique_ptr<ClipboardHistoryMenuModelAdapter> context_menu_;
// Handles events on the `context_menu_`.
std::unique_ptr<MenuDelegate> menu_delegate_;
// How the user last caused the `context_menu_` to show.
crosapi::mojom::ClipboardHistoryControllerShowSource last_menu_source_;
// Indicates whether the clipboard data has been replaced due to an
// in-progress clipboard history paste.
bool clipboard_data_replaced_ = false;
// Used to post asynchronous tasks when opening or closing the clipboard
// history menu. Note that those tasks have data races between each other.
// The timer can guarantee that at most one task is alive.
base::OneShotTimer menu_task_timer_;
// Indicates the count of pastes which are triggered through the clipboard
// history menu and are waiting for the confirmations from `ClipboardHistory`.
int pastes_to_be_confirmed_ = 0;
// Used to post a task to notify `observers_` of updates to clipboard history
// items.
base::OneShotTimer item_update_notification_timer_;
// True if there were available items in the last clipboard history update
// notification.
bool has_available_items_in_last_update_ = false;
// Created when a test requests that `GetHistoryValues()` wait for some work
// to be done before encoding finishes. Reset and recreated if the same test
// makes the request to pause `GetHistoryValues()` again.
std::unique_ptr<base::OneShotEvent> get_history_values_blocker_for_test_;
// The delay interval for restoring the clipboard buffer to its original
// state following a paste event.
std::optional<base::TimeDelta> buffer_restoration_delay_for_test_;
// Called when the first item view is selected after the clipboard history
// menu opens.
base::RepeatingClosure initial_item_selected_callback_for_test_;
// Called when a copy or paste finishes. Accepts the operation's success as an
// argument.
base::RepeatingCallback<void(bool)> confirmed_operation_callback_for_test_;
// A new bitmap to be written to the clipboard while existing images are being
// encoded during `GetHistoryValues()`, which will force `GetHistoryValues()`
// to re-run in order to encode this new bitmap. This member is marked mutable
// so it can be cleared once it has been written to the clipboard.
mutable SkBitmap new_bitmap_to_write_while_encoding_for_test_;
base::WeakPtrFactory<ClipboardHistoryControllerImpl> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_CLIPBOARD_CLIPBOARD_HISTORY_CONTROLLER_IMPL_H_