[SysUi download integration] Add "copy to clipboard" button
This CL adds a notification button to copy the download image to clipboard if the image download has completed. A demo has been attached to the issue. Bug: b/326122967 Change-Id: I4d035757bdea75a00941cab1c16a9d5ca2eb435e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5310539 Commit-Queue: Andrew Xu <andrewxu@chromium.org> Reviewed-by: David Black <dmblack@google.com> Cr-Commit-Position: refs/heads/main@{#1265967}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
178307719b
commit
f7c36899ec
ash
chrome/browser/ui/ash/download_status
display_manager.ccdisplay_metadata.hdisplay_test_util.ccdisplay_test_util.hholding_space_display_client.ccholding_space_display_client_browsertest.ccnotification_display_client.ccnotification_display_client_browsertest.cc
tools/metrics/actions
@ -7680,6 +7680,9 @@ To shut down the device, press and hold the power button on the device again.
|
||||
<message name="IDS_ASH_DOWNLOAD_COMMAND_TEXT_CANCEL" desc="Text of the command to cancel a download.">
|
||||
Cancel
|
||||
</message>
|
||||
<message name="IDS_ASH_DOWNLOAD_COMMAND_TEXT_COPY_TO_CLIPBOARD" desc="Text of the command to copy the download file to clipboard.">
|
||||
Copy to clipboard
|
||||
</message>
|
||||
<message name="IDS_ASH_DOWNLOAD_COMMAND_TEXT_PAUSE" desc="Text of the command to pause a download.">
|
||||
Pause
|
||||
</message>
|
||||
|
@ -0,0 +1 @@
|
||||
78af3668f6d2945de8f98d57b602be639ddb81e8
|
@ -25,6 +25,12 @@
|
||||
#include "chrome/browser/ui/ash/download_status/notification_display_client.h"
|
||||
#include "chromeos/crosapi/mojom/download_controller.mojom.h"
|
||||
#include "chromeos/crosapi/mojom/download_status_updater.mojom.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "third_party/blink/public/common/mime_util/mime_util.h"
|
||||
#include "ui/base/clipboard/clipboard_buffer.h"
|
||||
#include "ui/base/clipboard/file_info.h"
|
||||
#include "ui/base/clipboard/scoped_clipboard_writer.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
namespace ash::download_status {
|
||||
|
||||
@ -134,6 +140,15 @@ std::optional<std::u16string> GetText(
|
||||
return file_path.get().BaseName().LossyDisplayName();
|
||||
}
|
||||
|
||||
// Returns true if the file referred to by `file_path` is of an image MIME type.
|
||||
bool HasSupportedImageMimeType(const base::FilePath& file_path) {
|
||||
std::string mime_type;
|
||||
if (net::GetMimeTypeFromFile(file_path, &mime_type)) {
|
||||
return blink::IsSupportedImageMimeType(mime_type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Opens the download file specified by `file_path` under the file system
|
||||
// associated with `profile`.
|
||||
void OpenFile(Profile* profile, const base::FilePath& file_path) {
|
||||
@ -240,22 +255,38 @@ DisplayMetadata DisplayManager::CalculateDisplayMetadata(
|
||||
&kResumeIcon, IDS_ASH_DOWNLOAD_COMMAND_TEXT_RESUME,
|
||||
CommandType::kResume);
|
||||
}
|
||||
const base::FilePath& full_path = *download_status.full_path;
|
||||
switch (download_status.state) {
|
||||
case crosapi::mojom::DownloadState::kComplete:
|
||||
// NOTE: `kOpenFile` is not shown so it doesn't require an icon/text_id.
|
||||
command_infos.emplace_back(
|
||||
base::BindRepeating(
|
||||
&DisplayManager::PerformCommand, weak_ptr_factory_.GetWeakPtr(),
|
||||
CommandType::kOpenFile, *download_status.full_path),
|
||||
base::BindRepeating(&DisplayManager::PerformCommand,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
CommandType::kOpenFile, full_path),
|
||||
/*icon=*/nullptr, /*text_id=*/-1, CommandType::kOpenFile);
|
||||
|
||||
// NOTE: The `kShowInFolder` button does not have an icon.
|
||||
command_infos.emplace_back(
|
||||
base::BindRepeating(
|
||||
&DisplayManager::PerformCommand, weak_ptr_factory_.GetWeakPtr(),
|
||||
CommandType::kShowInFolder, *download_status.full_path),
|
||||
base::BindRepeating(&DisplayManager::PerformCommand,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
CommandType::kShowInFolder, full_path),
|
||||
/*icon=*/nullptr, IDS_ASH_DOWNLOAD_COMMAND_TEXT_SHOW_IN_FOLDER,
|
||||
CommandType::kShowInFolder);
|
||||
|
||||
// Add a command to copy the download file to clipboard if:
|
||||
// 1. `download_status` has a valid image; AND
|
||||
// 2. The download file is an image.
|
||||
// NOTE: The `kCopyToClipboard` button does not require an icon.
|
||||
if (const gfx::ImageSkia& image = download_status.image;
|
||||
!image.isNull() && !image.size().IsEmpty() &&
|
||||
HasSupportedImageMimeType(full_path)) {
|
||||
command_infos.emplace_back(
|
||||
base::BindRepeating(&DisplayManager::PerformCommand,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
CommandType::kCopyToClipboard, full_path),
|
||||
/*icon=*/nullptr, IDS_ASH_DOWNLOAD_COMMAND_TEXT_COPY_TO_CLIPBOARD,
|
||||
CommandType::kCopyToClipboard);
|
||||
}
|
||||
break;
|
||||
case crosapi::mojom::DownloadState::kInProgress:
|
||||
// NOTE: `kShowInBrowser` is not shown so doesn't require an icon/text_id.
|
||||
@ -284,7 +315,7 @@ DisplayMetadata DisplayManager::CalculateDisplayMetadata(
|
||||
}
|
||||
display_metadata.command_infos = std::move(command_infos);
|
||||
|
||||
display_metadata.file_path = *download_status.full_path;
|
||||
display_metadata.file_path = full_path;
|
||||
display_metadata.image = download_status.image;
|
||||
display_metadata.progress = GetProgress(download_status);
|
||||
display_metadata.secondary_text = download_status.status_text;
|
||||
@ -301,6 +332,13 @@ void DisplayManager::PerformCommand(
|
||||
download_status_updater_->Cancel(/*guid=*/std::get<std::string>(param),
|
||||
/*callback=*/base::DoNothing());
|
||||
break;
|
||||
case CommandType::kCopyToClipboard: {
|
||||
ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
|
||||
scw.WriteFilenames(ui::FileInfosToURIList(
|
||||
/*filenames=*/{ui::FileInfo(std::get<base::FilePath>(param),
|
||||
/*display_name=*/base::FilePath())}));
|
||||
break;
|
||||
}
|
||||
case CommandType::kOpenFile:
|
||||
OpenFile(profile_, std::get<base::FilePath>(param));
|
||||
break;
|
||||
|
@ -22,6 +22,7 @@ namespace ash::download_status {
|
||||
// Lists the types of commands that can be performed on a displayed download.
|
||||
enum class CommandType {
|
||||
kCancel,
|
||||
kCopyToClipboard,
|
||||
kOpenFile,
|
||||
kPause,
|
||||
kResume,
|
||||
|
@ -22,11 +22,12 @@ constexpr int64_t kUnknownTotalBytes = -1;
|
||||
|
||||
crosapi::mojom::DownloadStatusPtr CreateDownloadStatus(
|
||||
Profile* profile,
|
||||
std::string_view extension,
|
||||
crosapi::mojom::DownloadState state,
|
||||
crosapi::mojom::DownloadProgressPtr progress) {
|
||||
crosapi::mojom::DownloadStatusPtr download_status =
|
||||
crosapi::mojom::DownloadStatus::New();
|
||||
download_status->full_path = test::CreateFile(profile);
|
||||
download_status->full_path = test::CreateFile(profile, extension);
|
||||
download_status->guid = base::UnguessableToken::Create().ToString();
|
||||
download_status->progress = std::move(progress);
|
||||
download_status->state = state;
|
||||
@ -36,10 +37,11 @@ crosapi::mojom::DownloadStatusPtr CreateDownloadStatus(
|
||||
|
||||
crosapi::mojom::DownloadStatusPtr CreateInProgressDownloadStatus(
|
||||
Profile* profile,
|
||||
std::string_view extension,
|
||||
int64_t received_bytes,
|
||||
const std::optional<int64_t>& total_bytes) {
|
||||
return CreateDownloadStatus(
|
||||
profile, crosapi::mojom::DownloadState::kInProgress,
|
||||
profile, extension, crosapi::mojom::DownloadState::kInProgress,
|
||||
crosapi::mojom::DownloadProgress::New(
|
||||
/*loop=*/false, received_bytes,
|
||||
total_bytes.value_or(kUnknownTotalBytes), /*visible=*/true));
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define CHROME_BROWSER_UI_ASH_DOWNLOAD_STATUS_DISPLAY_TEST_UTIL_H_
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "chromeos/crosapi/mojom/download_status_updater.mojom.h"
|
||||
|
||||
@ -13,10 +14,11 @@ class Profile;
|
||||
|
||||
namespace ash::download_status {
|
||||
|
||||
// Creates a download status associated with a file under the downloads
|
||||
// directory of `profile`.
|
||||
// Creates a download status associated with a file with the specified
|
||||
// `extension` under the downloads directory of `profile`.
|
||||
crosapi::mojom::DownloadStatusPtr CreateDownloadStatus(
|
||||
Profile* profile,
|
||||
std::string_view extension,
|
||||
crosapi::mojom::DownloadState state,
|
||||
crosapi::mojom::DownloadProgressPtr progress);
|
||||
|
||||
@ -24,6 +26,7 @@ crosapi::mojom::DownloadStatusPtr CreateDownloadStatus(
|
||||
// with a file under the downloads directory of `profile`.
|
||||
crosapi::mojom::DownloadStatusPtr CreateInProgressDownloadStatus(
|
||||
Profile* profile,
|
||||
std::string_view extension,
|
||||
int64_t received_bytes,
|
||||
const std::optional<int64_t>& total_bytes = std::nullopt);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "chrome/browser/ui/ash/download_status/holding_space_display_client.h"
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@ -28,14 +29,17 @@ namespace ash::download_status {
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns the command ID corresponding to the given command type.
|
||||
// Returns the command ID corresponding to the given command type if any. If
|
||||
// there is no such command ID, returns `std::nullopt`.
|
||||
// NOTE: It is fine to map both `CommandType::kOpenFile` and
|
||||
// `CommandType::kShowInBrowser` to `kOpenItem`, because `kOpenItem` is not
|
||||
// accessible from a holding space chip's context menu.
|
||||
HoldingSpaceCommandId ConvertCommandTypeToId(CommandType type) {
|
||||
std::optional<HoldingSpaceCommandId> ConvertCommandTypeToId(CommandType type) {
|
||||
switch (type) {
|
||||
case CommandType::kCancel:
|
||||
return HoldingSpaceCommandId::kCancelItem;
|
||||
case CommandType::kCopyToClipboard:
|
||||
return std::nullopt;
|
||||
case CommandType::kOpenFile:
|
||||
return HoldingSpaceCommandId::kOpenItem;
|
||||
case CommandType::kPause:
|
||||
@ -51,12 +55,16 @@ HoldingSpaceCommandId ConvertCommandTypeToId(CommandType type) {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the holding space item action corresponding to `type`.
|
||||
holding_space_metrics::ItemAction ConvertCommandTypeToAction(CommandType type) {
|
||||
// Returns the holding space item action corresponding to `type` if any. If
|
||||
// there is no such action, returns `std::nullopt`.
|
||||
std::optional<holding_space_metrics::ItemAction> ConvertCommandTypeToAction(
|
||||
CommandType type) {
|
||||
using ItemAction = holding_space_metrics::ItemAction;
|
||||
switch (type) {
|
||||
case CommandType::kCancel:
|
||||
return ItemAction::kCancel;
|
||||
case CommandType::kCopyToClipboard:
|
||||
return std::nullopt;
|
||||
case CommandType::kOpenFile:
|
||||
return ItemAction::kLaunch;
|
||||
case CommandType::kPause:
|
||||
@ -121,23 +129,31 @@ void HoldingSpaceDisplayClient::AddOrUpdate(
|
||||
// Generate in-progress commands from `display_metadata`.
|
||||
std::vector<HoldingSpaceItem::InProgressCommand> in_progress_commands;
|
||||
for (const auto& command_info : display_metadata.command_infos) {
|
||||
if (const HoldingSpaceCommandId id =
|
||||
ConvertCommandTypeToId(command_info.type);
|
||||
holding_space_util::IsInProgressCommand(id)) {
|
||||
in_progress_commands.emplace_back(
|
||||
id, command_info.text_id, command_info.icon,
|
||||
base::BindRepeating(
|
||||
[](holding_space_metrics::ItemAction action,
|
||||
const base::RepeatingClosure& command_callback,
|
||||
const HoldingSpaceItem* item, HoldingSpaceCommandId command_id,
|
||||
holding_space_metrics::EventSource event_source) {
|
||||
command_callback.Run();
|
||||
holding_space_metrics::RecordItemAction(
|
||||
/*items=*/{item}, action, event_source);
|
||||
},
|
||||
ConvertCommandTypeToAction(command_info.type),
|
||||
command_info.command_callback));
|
||||
const std::optional<HoldingSpaceCommandId> id =
|
||||
ConvertCommandTypeToId(command_info.type);
|
||||
const std::optional<holding_space_metrics::ItemAction> item_action =
|
||||
ConvertCommandTypeToAction(command_info.type);
|
||||
|
||||
// Skip `command_info` if:
|
||||
// 1. It does not have a corresponding ID; OR
|
||||
// 2. Its corresponding ID is not for an in-progress command; OR
|
||||
// 3. It does not have a corresponding item action.
|
||||
if (!id || !holding_space_util::IsInProgressCommand(*id) || !item_action) {
|
||||
continue;
|
||||
}
|
||||
|
||||
in_progress_commands.emplace_back(
|
||||
*id, command_info.text_id, command_info.icon,
|
||||
base::BindRepeating(
|
||||
[](holding_space_metrics::ItemAction action,
|
||||
const base::RepeatingClosure& command_callback,
|
||||
const HoldingSpaceItem* item, HoldingSpaceCommandId command_id,
|
||||
holding_space_metrics::EventSource event_source) {
|
||||
command_callback.Run();
|
||||
holding_space_metrics::RecordItemAction(
|
||||
/*items=*/{item}, action, event_source);
|
||||
},
|
||||
*item_action, command_info.command_callback));
|
||||
}
|
||||
|
||||
// Specify the backing file.
|
||||
|
@ -137,17 +137,18 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
Profile* const profile = ProfileManager::GetActiveUserProfile();
|
||||
crosapi::mojom::DownloadStatusPtr in_progress_download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
in_progress_download->cancellable = true;
|
||||
Update(in_progress_download->Clone());
|
||||
crosapi::mojom::DownloadStatusPtr completed_download =
|
||||
CreateDownloadStatus(profile, crosapi::mojom::DownloadState::kComplete,
|
||||
crosapi::mojom::DownloadProgress::New(
|
||||
/*loop=*/false,
|
||||
/*received_bytes=*/1024,
|
||||
/*total_bytes=*/1024,
|
||||
/*visible=*/false));
|
||||
crosapi::mojom::DownloadStatusPtr completed_download = CreateDownloadStatus(
|
||||
profile, /*extension=*/"txt", crosapi::mojom::DownloadState::kComplete,
|
||||
crosapi::mojom::DownloadProgress::New(
|
||||
/*loop=*/false,
|
||||
/*received_bytes=*/1024,
|
||||
/*total_bytes=*/1024,
|
||||
/*visible=*/false));
|
||||
Update(completed_download->Clone());
|
||||
test_api().Show();
|
||||
|
||||
@ -258,12 +259,13 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
Profile* const profile = ProfileManager::GetActiveUserProfile();
|
||||
crosapi::mojom::DownloadStatusPtr in_progress_download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
in_progress_download->cancellable = true;
|
||||
Update(in_progress_download->Clone());
|
||||
crosapi::mojom::DownloadStatusPtr completed_download = CreateDownloadStatus(
|
||||
profile, crosapi::mojom::DownloadState::kComplete,
|
||||
profile, /*extension=*/"txt", crosapi::mojom::DownloadState::kComplete,
|
||||
crosapi::mojom::DownloadProgress::New(
|
||||
/*loop=*/false,
|
||||
/*received_bytes=*/1024, /*total_bytes=*/1024, /*visible=*/false));
|
||||
@ -367,14 +369,14 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
ClickCompletedDownloadChip) {
|
||||
// Add a completed download.
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
crosapi::mojom::DownloadState::kComplete,
|
||||
crosapi::mojom::DownloadProgress::New(
|
||||
/*loop=*/false,
|
||||
/*received_bytes=*/1024,
|
||||
/*total_bytes=*/1024,
|
||||
/*visible=*/false));
|
||||
crosapi::mojom::DownloadStatusPtr download = CreateDownloadStatus(
|
||||
ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt", crosapi::mojom::DownloadState::kComplete,
|
||||
crosapi::mojom::DownloadProgress::New(
|
||||
/*loop=*/false,
|
||||
/*received_bytes=*/1024,
|
||||
/*total_bytes=*/1024,
|
||||
/*visible=*/false));
|
||||
Update(download->Clone());
|
||||
test_api().Show();
|
||||
|
||||
@ -416,6 +418,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
// Add an in-progress download.
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
Update(download->Clone());
|
||||
@ -456,6 +459,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest, CompleteDownload) {
|
||||
Profile* const active_profile = ProfileManager::GetActiveUserProfile();
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(active_profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
Update(download->Clone());
|
||||
@ -535,6 +539,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest, CompleteDownload) {
|
||||
// Add a new in-progress download with the duplicate download guid.
|
||||
crosapi::mojom::DownloadStatusPtr duplicate_download =
|
||||
CreateInProgressDownloadStatus(active_profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
duplicate_download->guid = download->guid;
|
||||
@ -548,8 +553,9 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest, CompleteDownload) {
|
||||
IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
IndeterminateDownload) {
|
||||
// Create a download with an unknown total bytes count.
|
||||
crosapi::mojom::DownloadStatusPtr download = CreateInProgressDownloadStatus(
|
||||
ProfileManager::GetActiveUserProfile(), /*received_bytes=*/0);
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt", /*received_bytes=*/0);
|
||||
Update(download->Clone());
|
||||
test_api().Show();
|
||||
|
||||
@ -568,6 +574,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
// could happen when a download is blocked.
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
download->progress->visible = false;
|
||||
@ -592,6 +599,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
InterruptDownload) {
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
Update(download->Clone());
|
||||
@ -610,6 +618,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
PauseAndResumeDownloadViaContextMenu) {
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
download->pausable = true;
|
||||
@ -689,6 +698,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
PauseAndResumeDownloadViaSecondaryAction) {
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
download->pausable = true;
|
||||
@ -773,6 +783,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest, SecondaryLabel) {
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
Update(download->Clone());
|
||||
@ -806,6 +817,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
ServiceSuspendedDuringDownload) {
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
Update(download->Clone());
|
||||
@ -849,6 +861,7 @@ IN_PROC_BROWSER_TEST_F(HoldingSpaceDisplayClientBrowserTest,
|
||||
// Create an in-progress download that can be canceled and paused.
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
download->cancellable = true;
|
||||
|
@ -144,6 +144,8 @@ const char* GetMetricString(CommandType command) {
|
||||
switch (command) {
|
||||
case CommandType::kCancel:
|
||||
return "DownloadNotificationV2.Button_Cancel";
|
||||
case CommandType::kCopyToClipboard:
|
||||
return "DownloadNotificationV2.Button_CopyToClipboard";
|
||||
case CommandType::kOpenFile:
|
||||
return "DownloadNotificationV2.Click_Completed";
|
||||
case CommandType::kPause:
|
||||
@ -167,6 +169,7 @@ bool IsBodyClickCommandType(CommandType command) {
|
||||
case CommandType::kShowInBrowser:
|
||||
return true;
|
||||
case CommandType::kCancel:
|
||||
case CommandType::kCopyToClipboard:
|
||||
case CommandType::kPause:
|
||||
case CommandType::kResume:
|
||||
case CommandType::kShowInFolder:
|
||||
@ -180,6 +183,7 @@ bool IsBodyClickCommandType(CommandType command) {
|
||||
bool IsButtonClickCommandType(CommandType command) {
|
||||
switch (command) {
|
||||
case CommandType::kCancel:
|
||||
case CommandType::kCopyToClipboard:
|
||||
case CommandType::kPause:
|
||||
case CommandType::kResume:
|
||||
case CommandType::kShowInFolder:
|
||||
|
@ -53,6 +53,8 @@
|
||||
#include "ui/aura/env_observer.h"
|
||||
#include "ui/aura/test/find_window.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/base/clipboard/clipboard.h"
|
||||
#include "ui/base/clipboard/clipboard_buffer.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/gfx/image/image_unittest_util.h"
|
||||
#include "ui/message_center/public/cpp/notification.h"
|
||||
@ -75,7 +77,9 @@ using ::testing::_;
|
||||
using ::testing::AllOf;
|
||||
using ::testing::Contains;
|
||||
using ::testing::Each;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
using ::testing::Field;
|
||||
using ::testing::Mock;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Not;
|
||||
@ -123,6 +127,8 @@ int GetCommandTextId(CommandType command_type) {
|
||||
switch (command_type) {
|
||||
case CommandType::kCancel:
|
||||
return IDS_ASH_DOWNLOAD_COMMAND_TEXT_CANCEL;
|
||||
case CommandType::kCopyToClipboard:
|
||||
return IDS_ASH_DOWNLOAD_COMMAND_TEXT_COPY_TO_CLIPBOARD;
|
||||
case CommandType::kOpenFile:
|
||||
NOTREACHED_NORETURN();
|
||||
case CommandType::kPause:
|
||||
@ -251,6 +257,7 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest, CancelDownload) {
|
||||
}));
|
||||
crosapi::mojom::DownloadStatusPtr uncancellable_download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
uncancellable_download->cancellable = false;
|
||||
@ -278,6 +285,7 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest, CancelDownload) {
|
||||
}));
|
||||
crosapi::mojom::DownloadStatusPtr cancellable_download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
cancellable_download->cancellable = true;
|
||||
@ -335,13 +343,13 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest,
|
||||
[¬ification_id](const message_center::Notification& notification) {
|
||||
notification_id = notification.id();
|
||||
}));
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateDownloadStatus(profile, crosapi::mojom::DownloadState::kComplete,
|
||||
crosapi::mojom::DownloadProgress::New(
|
||||
/*loop=*/false,
|
||||
/*received_bytes=*/1024,
|
||||
/*total_bytes=*/1024,
|
||||
/*visible=*/false));
|
||||
crosapi::mojom::DownloadStatusPtr download = CreateDownloadStatus(
|
||||
profile, /*extension=*/"txt", crosapi::mojom::DownloadState::kComplete,
|
||||
crosapi::mojom::DownloadProgress::New(
|
||||
/*loop=*/false,
|
||||
/*received_bytes=*/1024,
|
||||
/*total_bytes=*/1024,
|
||||
/*visible=*/false));
|
||||
Update(download->Clone());
|
||||
Mock::VerifyAndClearExpectations(&service_observer());
|
||||
|
||||
@ -384,6 +392,7 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest,
|
||||
}));
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
Update(download->Clone());
|
||||
@ -418,9 +427,10 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest,
|
||||
// still show.
|
||||
IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest, CompleteDownload) {
|
||||
Profile* const profile = ProfileManager::GetActiveUserProfile();
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateDownloadStatus(profile, crosapi::mojom::DownloadState::kInProgress,
|
||||
/*progress=*/nullptr);
|
||||
crosapi::mojom::DownloadStatusPtr download = CreateDownloadStatus(
|
||||
profile,
|
||||
/*extension=*/"txt", crosapi::mojom::DownloadState::kInProgress,
|
||||
/*progress=*/nullptr);
|
||||
EXPECT_FALSE(download->target_file_path);
|
||||
std::string notification_id;
|
||||
|
||||
@ -544,6 +554,7 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest,
|
||||
Profile* const profile = ProfileManager::GetActiveUserProfile();
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
Update(download->Clone());
|
||||
@ -580,12 +591,14 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest, ImageDownload) {
|
||||
notification_id = notification.id();
|
||||
}));
|
||||
|
||||
// Create a download.
|
||||
// Create an image download.
|
||||
Profile* const profile = ProfileManager::GetActiveUserProfile();
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
crosapi::mojom::DownloadStatusPtr download = CreateDownloadStatus(
|
||||
profile,
|
||||
/*extension=*/"png", crosapi::mojom::DownloadState::kInProgress,
|
||||
crosapi::mojom::DownloadProgress::New(
|
||||
/*loop=*/false, /*received_bytes=*/0,
|
||||
/*total_bytes=*/1024, /*visible=*/true));
|
||||
Update(download->Clone());
|
||||
Mock::VerifyAndClearExpectations(&service_observer());
|
||||
|
||||
@ -614,6 +627,49 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest, ImageDownload) {
|
||||
*large_image_view->original_image().bitmap(),
|
||||
gfx::test::CreateBitmap(/*width=*/360,
|
||||
/*height=*/240, image_color)));
|
||||
|
||||
// An in-progress image download's notification should not have a 'Copy to
|
||||
// clipboard' button.
|
||||
const std::u16string copy_to_clipboard_button_text =
|
||||
l10n_util::GetStringUTF16(
|
||||
GetCommandTextId(CommandType::kCopyToClipboard));
|
||||
EXPECT_THAT(
|
||||
popup_view->GetActionButtonsForTest(),
|
||||
Not(Contains(Pointee(Property(&views::LabelButton::GetText,
|
||||
Eq(copy_to_clipboard_button_text))))));
|
||||
|
||||
// Complete `download`. Then check action buttons.
|
||||
MarkDownloadStatusCompleted(*download);
|
||||
Update(download->Clone());
|
||||
const std::vector<raw_ptr<views::LabelButton, VectorExperimental>>
|
||||
action_buttons = popup_view->GetActionButtonsForTest();
|
||||
EXPECT_THAT(
|
||||
action_buttons,
|
||||
ElementsAre(
|
||||
Pointee(Property(&views::LabelButton::GetText,
|
||||
Eq(l10n_util::GetStringUTF16(
|
||||
GetCommandTextId(CommandType::kShowInFolder))))),
|
||||
Pointee(Property(&views::LabelButton::GetText,
|
||||
Eq(copy_to_clipboard_button_text)))));
|
||||
|
||||
// Click the 'Copy to clipboard' button. Then verify the click is recorded.
|
||||
base::UserActionTester tester;
|
||||
auto copy_to_clipboard_button_iter =
|
||||
base::ranges::find(action_buttons, copy_to_clipboard_button_text,
|
||||
&views::LabelButton::GetText);
|
||||
ASSERT_NE(copy_to_clipboard_button_iter, action_buttons.cend());
|
||||
test::Click(*copy_to_clipboard_button_iter, ui::EF_NONE);
|
||||
EXPECT_EQ(
|
||||
tester.GetActionCount("DownloadNotificationV2.Button_CopyToClipboard"),
|
||||
1);
|
||||
|
||||
// Verify the filename in the clipboard as expected.
|
||||
base::test::TestFuture<std::vector<ui::FileInfo>> test_future;
|
||||
ui::Clipboard::GetForCurrentThread()->ReadFilenames(
|
||||
ui::ClipboardBuffer::kCopyPaste,
|
||||
/*data_dst=*/nullptr, test_future.GetCallback());
|
||||
EXPECT_THAT(test_future.Get(),
|
||||
ElementsAre(Field(&ui::FileInfo::path, *download->full_path)));
|
||||
}
|
||||
|
||||
// Verifies that the notification of a download with an unknown total bytes
|
||||
@ -630,6 +686,7 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest,
|
||||
Profile* const profile = ProfileManager::GetActiveUserProfile();
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0);
|
||||
|
||||
Update(download->Clone());
|
||||
@ -668,6 +725,7 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest,
|
||||
}));
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(ProfileManager::GetActiveUserProfile(),
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
Update(download->Clone());
|
||||
@ -691,6 +749,7 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest,
|
||||
}));
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
download->pausable = true;
|
||||
@ -803,6 +862,7 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest, ShowInFolder) {
|
||||
}));
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
Update(download->Clone());
|
||||
@ -860,6 +920,7 @@ IN_PROC_BROWSER_TEST_F(NotificationDisplayClientBrowserTest,
|
||||
Profile* const profile = ProfileManager::GetActiveUserProfile();
|
||||
crosapi::mojom::DownloadStatusPtr download =
|
||||
CreateInProgressDownloadStatus(profile,
|
||||
/*extension=*/"txt",
|
||||
/*received_bytes=*/0,
|
||||
/*total_bytes=*/1024);
|
||||
download->cancellable = true;
|
||||
|
@ -9512,6 +9512,15 @@ should be able to be added at any place in this file.
|
||||
</description>
|
||||
</action>
|
||||
|
||||
<action name="DownloadNotificationV2.Button_CopyToClipboard">
|
||||
<owner>andrewxu@chromium.org</owner>
|
||||
<owner>cros-system-ui-productivity-eng@google.com</owner>
|
||||
<description>
|
||||
User clicks "Copy to clipboard" button on a download notification
|
||||
with the downloads integration V2 feature enabled.
|
||||
</description>
|
||||
</action>
|
||||
|
||||
<action name="DownloadNotificationV2.Button_Pause">
|
||||
<owner>andrewxu@chromium.org</owner>
|
||||
<owner>cros-system-ui-productivity-eng@google.com</owner>
|
||||
|
Reference in New Issue
Block a user