Skip to content

Commit

Permalink
[M110] Support copying a file from the download bubble
Browse files Browse the repository at this point in the history
This CL registers the DownloadBubbleRowView to listen for the copy
accelerator so that we can write the file to clipboard.

(cherry picked from commit 214f05e)

Bug: 1394776
Change-Id: I559e5d944b10cf79eddf8087417a381cf3f60a66
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4093037
Commit-Queue: Daniel Rubery <drubery@chromium.org>
Reviewed-by: Xinghui Lu <xinghuilu@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1085049}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4157872
Cr-Commit-Position: refs/branch-heads/5481@{#284}
Cr-Branched-From: 130f3e4-refs/heads/main@{#1084008}
  • Loading branch information
Daniel Rubery authored and Chromium LUCI CQ committed Jan 13, 2023
1 parent ba2820f commit 23ae4eb
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/metrics/histogram_functions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/bubble/download_bubble_controller.h"
Expand All @@ -21,9 +22,11 @@
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/download/bubble/download_bubble_row_list_view.h"
#include "chrome/browser/ui/views/download/download_shelf_context_menu_view.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/grit/generated_resources.h"
#include "components/download/public/common/download_item.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/time_format.h"
#include "ui/base/metadata/metadata_header_macros.h"
Expand Down Expand Up @@ -178,13 +181,16 @@ void DownloadBubbleRowView::AddedToWidget() {
auto* focus_manager = GetFocusManager();
if (focus_manager) {
focus_manager->AddFocusChangeListener(this);
RegisterAccelerators(focus_manager);
}
}

void DownloadBubbleRowView::RemovedFromWidget() {
auto* focus_manager = GetFocusManager();
if (focus_manager)
if (focus_manager) {
focus_manager->RemoveFocusChangeListener(this);
UnregisterAccelerators(focus_manager);
}
}

void DownloadBubbleRowView::OnThemeChanged() {
Expand Down Expand Up @@ -844,5 +850,65 @@ void DownloadBubbleRowView::AnnounceInProgressAlert() {
model_->GetInProgressAccessibleAlertText());
}

bool DownloadBubbleRowView::AcceleratorPressed(
const ui::Accelerator& accelerator) {
if (model_->GetState() != download::DownloadItem::COMPLETE) {
return false;
}

// The only accelerator we registered is for copy, so we know that's what
// `accelerator` contains. If DCHECKs are enabled, we can confirm that.
#if DCHECK_IS_ON()
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
ui::Accelerator registered_accelerator;
if (browser_view &&
browser_view->GetAccelerator(IDC_COPY, &registered_accelerator)) {
DCHECK(accelerator == registered_accelerator);
}
#endif

ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
std::string uri_list = ui::FileInfosToURIList({ui::FileInfo(
model_->GetTargetFilePath(), model_->GetFileNameToReportUser())});
scw.WriteFilenames(uri_list);
return true;
}

bool DownloadBubbleRowView::CanHandleAccelerators() const {
bool focused = Contains(GetFocusManager()->GetFocusedView());
return focused;
}

void DownloadBubbleRowView::RegisterAccelerators(
views::FocusManager* focus_manager) {
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
if (!browser_view) {
return;
}

ui::Accelerator accelerator;
if (!browser_view->GetAccelerator(IDC_COPY, &accelerator)) {
return;
}

focus_manager->RegisterAccelerator(
accelerator, ui::AcceleratorManager::kNormalPriority, this);
}

void DownloadBubbleRowView::UnregisterAccelerators(
views::FocusManager* focus_manager) {
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
if (!browser_view) {
return;
}

ui::Accelerator accelerator;
if (!browser_view->GetAccelerator(IDC_COPY, &accelerator)) {
return;
}

focus_manager->UnregisterAccelerator(accelerator, this);
}

BEGIN_METADATA(DownloadBubbleRowView, views::View)
END_METADATA
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ class DownloadBubbleRowView : public views::View,
const gfx::Point& point,
ui::MenuSourceType source_type) override;

// Overrides ui::AcceleratorTarget
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
bool CanHandleAccelerators() const override;

DownloadUIModel* model() { return model_.get(); }

DownloadUIModel::BubbleUIInfo& ui_info() { return ui_info_; }
Expand Down Expand Up @@ -129,6 +133,10 @@ class DownloadBubbleRowView : public views::View,

void AnnounceInProgressAlert();

// Registers/unregisters copy accelerator for copy/paste support.
void RegisterAccelerators(views::FocusManager* focus_manager);
void UnregisterAccelerators(views::FocusManager* focus_manager);

// The icon for the file. We get platform-specific icons from IconLoader.
raw_ptr<views::ImageView> icon_ = nullptr;
raw_ptr<views::ImageView> subpage_icon_ = nullptr;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/download/bubble/download_bubble_row_view.h"

#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
#include "components/download/public/common/mock_download_item.h"
#include "components/safe_browsing/core/common/features.h"
#include "content/public/browser/download_item_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/test/test_clipboard.h"

namespace {

using ::testing::NiceMock;
using ::testing::Return;
using ::testing::ReturnRefOfCopy;

class DownloadBubbleRowViewTest : public TestWithBrowserView {
public:
DownloadBubbleRowViewTest() {
scoped_feature_list_.InitAndEnableFeature(safe_browsing::kDownloadBubble);
}

DownloadBubbleRowViewTest(const DownloadBubbleRowViewTest&) = delete;
DownloadBubbleRowViewTest& operator=(const DownloadBubbleRowViewTest&) =
delete;

void SetUp() override {
TestWithBrowserView::SetUp();

content::DownloadItemUtils::AttachInfoForTesting(
&download_item_, browser()->profile(), nullptr);
ON_CALL(download_item_, GetRerouteInfo())
.WillByDefault(testing::ReturnRefOfCopy(
enterprise_connectors::DownloadItemRerouteInfo()));

DownloadToolbarButtonView* button =
browser_view()->toolbar()->download_button();
row_list_view_ = std::make_unique<DownloadBubbleRowListView>(
/*is_partial_view=*/true, browser());
row_view_ = std::make_unique<DownloadBubbleRowView>(
DownloadItemModel::Wrap(&download_item_), row_list_view_.get(),
button->bubble_controller(), button, browser());
}

DownloadBubbleRowView* row_view() { return row_view_.get(); }
download::MockDownloadItem* download_item() { return &download_item_; }

private:
base::test::ScopedFeatureList scoped_feature_list_;
NiceMock<download::MockDownloadItem> download_item_;
std::unique_ptr<DownloadBubbleRowListView> row_list_view_;
std::unique_ptr<DownloadBubbleRowView> row_view_;
};

TEST_F(DownloadBubbleRowViewTest, CopyAcceleratorCopiesFile) {
#if BUILDFLAG(IS_WIN)
base::FilePath target_path(FILE_PATH_LITERAL("\\test.exe"));
#else
base::FilePath target_path(FILE_PATH_LITERAL("/test.exe"));
#endif
ON_CALL(*download_item(), GetState())
.WillByDefault(Return(download::DownloadItem::COMPLETE));
ON_CALL(*download_item(), GetTargetFilePath())
.WillByDefault(ReturnRefOfCopy(target_path));

ui::TestClipboard* clipboard = ui::TestClipboard::CreateForCurrentThread();

ui::Accelerator accelerator;
ASSERT_TRUE(browser_view()->GetAccelerator(IDC_COPY, &accelerator));

row_view()->AcceleratorPressed(accelerator);

std::vector<ui::FileInfo> filenames;
clipboard->ReadFilenames(ui::ClipboardBuffer::kCopyPaste, nullptr,
&filenames);
ASSERT_EQ(filenames.size(), 1u);
EXPECT_EQ(filenames[0].path, target_path);

clipboard->DestroyClipboardForCurrentThread();
}

} // namespace
1 change: 1 addition & 0 deletions chrome/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -8808,6 +8808,7 @@ test("unit_tests") {
"../browser/signin/signin_ui_util_unittest.cc",
"../browser/signin/signin_util_unittest.cc",
"../browser/ui/signin/profile_customization_synced_theme_waiter_unittest.cc",
"../browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc",
"../browser/ui/views/download/bubble/download_bubble_security_view_unittest.cc",
"../browser/ui/views/sharing/sharing_dialog_view_unittest.cc",
"../browser/ui/webui/signin/signin_error_handler_unittest.cc",
Expand Down

0 comments on commit 23ae4eb

Please sign in to comment.