Commit cbf5f453 authored by Joel Hockey's avatar Joel Hockey Committed by Commit Bot

Move drag drop file data conversions info FileHelper

Refactor only change.

Move data conversions into FileHelper where path translation and file
sharing for VMs can be done.

The current code assumes only Arc is using this code, but we will soon
support crostini and pluginvm.

FileHelper::GetFilenames receives a list of files from the source window
and returns a list of ui::FileInfo.  To support this,
DragDropOperation::GetFilenames has been refactored to take FileHelper
and aura::Window*.

FileHelper::GetMimeTypeForUriList now takes target window since the mime
type will be different based on target.

FileHelper::GetUrlFromPath changed to SendFileInfo which takes a
callback to run when data is ready. The async callback allows files to
be shared with a VM before sending the data.

FileHelper::GetUrlsFromPickle changed to SendPickle which also takes a
callback to run when data is ready.

Bug: 1144138
Change-Id: I0356d4681705df5be174ac1debff51f4903eb742
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2531087
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827027}
parent 42f8dfb0
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
#include "chrome/browser/exo_parts.h" #include "chrome/browser/exo_parts.h"
#include "base/memory/ptr_util.h" #include <string>
#include <vector>
#include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/ash_switches.h"
#include "ash/public/cpp/external_arc/keyboard/arc_input_method_surface_manager.h" #include "ash/public/cpp/external_arc/keyboard/arc_input_method_surface_manager.h"
...@@ -12,9 +13,18 @@ ...@@ -12,9 +13,18 @@
#include "ash/public/cpp/external_arc/overlay/arc_overlay_manager.h" #include "ash/public/cpp/external_arc/overlay/arc_overlay_manager.h"
#include "ash/public/cpp/external_arc/toast/arc_toast_surface_manager.h" #include "ash/public/cpp/external_arc/toast/arc_toast_surface_manager.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "base/bind.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/chromeos/crostini/crostini_shelf_utils.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/file_manager/app_id.h" #include "chrome/browser/chromeos/file_manager/app_id.h"
#include "chrome/browser/chromeos/file_manager/fileapi_util.h" #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
#include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/chromeos/file_manager/path_util.h"
...@@ -25,12 +35,16 @@ ...@@ -25,12 +35,16 @@
#include "components/user_manager/user_manager.h" #include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/common/drop_data.h" #include "content/public/common/drop_data.h"
#include "net/base/filename_util.h"
#include "storage/browser/file_system/file_system_context.h" #include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_url.h" #include "storage/browser/file_system/file_system_url.h"
#include "storage/common/file_system/file_system_types.h"
#include "ui/base/dragdrop/file_info/file_info.h"
namespace { namespace {
constexpr char kMimeTypeArcUriList[] = "application/x-arc-uri-list"; constexpr char kMimeTypeArcUriList[] = "application/x-arc-uri-list";
constexpr char kUriListSeparator[] = "\r\n";
storage::FileSystemContext* GetFileSystemContext() { storage::FileSystemContext* GetFileSystemContext() {
// Obtains the primary profile. // Obtains the primary profile.
...@@ -69,39 +83,84 @@ void GetFileSystemUrlsFromPickle( ...@@ -69,39 +83,84 @@ void GetFileSystemUrlsFromPickle(
} }
} }
void SendArcUrls(exo::FileHelper::SendDataCallback callback,
const std::vector<GURL>& urls) {
std::vector<std::string> lines;
for (const GURL& url : urls) {
if (!url.is_valid())
continue;
lines.emplace_back(url.spec());
}
// Arc requires UTF16 for data.
base::string16 data =
base::UTF8ToUTF16(base::JoinString(lines, kUriListSeparator));
std::move(callback).Run(base::RefCountedString16::TakeString(&data));
}
class ChromeFileHelper : public exo::FileHelper { class ChromeFileHelper : public exo::FileHelper {
public: public:
ChromeFileHelper() = default; ChromeFileHelper() = default;
~ChromeFileHelper() override = default; ~ChromeFileHelper() override = default;
// exo::FileHelper: // exo::FileHelper:
std::string GetMimeTypeForUriList() const override { std::vector<ui::FileInfo> GetFilenames(
aura::Window* source,
const std::vector<uint8_t>& data) const override {
// TODO(crbug.com/1144138): We must translate the path if this was received
// from a VM. E.g. if this was from crostini as
// file:///home/username/file.txt, we translate to
// file:///media/fuse/crostini_<hash>_termina_penguin/file.txt.
std::string lines(data.begin(), data.end());
std::vector<ui::FileInfo> filenames;
base::FilePath path;
storage::FileSystemURL url;
for (const base::StringPiece& line : base::SplitStringPiece(
lines, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
if (!net::FileURLToFilePath(GURL(line), &path))
continue;
filenames.emplace_back(ui::FileInfo(path, base::FilePath()));
}
return filenames;
}
std::string GetMimeTypeForUriList(aura::Window* target) const override {
return kMimeTypeArcUriList; return kMimeTypeArcUriList;
} }
bool GetUrlFromPath(aura::Window* target, void SendFileInfo(aura::Window* target,
const base::FilePath& path, const std::vector<ui::FileInfo>& files,
GURL* out) override { exo::FileHelper::SendDataCallback callback) const override {
return file_manager::util::ConvertPathToArcUrl(path, out); // TODO(crbug.com/1144138): Translate path and possibly share files with VM.
std::vector<std::string> lines;
GURL url;
for (const auto& info : files) {
if (file_manager::util::ConvertPathToArcUrl(info.path, &url)) {
lines.emplace_back(url.spec());
}
}
base::string16 data =
base::UTF8ToUTF16(base::JoinString(lines, kUriListSeparator));
std::move(callback).Run(base::RefCountedString16::TakeString(&data));
} }
bool HasUrlsInPickle(const base::Pickle& pickle) override { bool HasUrlsInPickle(const base::Pickle& pickle) const override {
std::vector<storage::FileSystemURL> file_system_urls; std::vector<storage::FileSystemURL> file_system_urls;
GetFileSystemUrlsFromPickle(pickle, &file_system_urls); GetFileSystemUrlsFromPickle(pickle, &file_system_urls);
return !file_system_urls.empty(); return !file_system_urls.empty();
} }
void GetUrlsFromPickle(aura::Window* target, void SendPickle(aura::Window* target,
const base::Pickle& pickle, const base::Pickle& pickle,
UrlsFromPickleCallback callback) override { exo::FileHelper::SendDataCallback callback) override {
// TODO(crbug.com/1144138): Translate path and possibly share files with VM.
std::vector<storage::FileSystemURL> file_system_urls; std::vector<storage::FileSystemURL> file_system_urls;
GetFileSystemUrlsFromPickle(pickle, &file_system_urls); GetFileSystemUrlsFromPickle(pickle, &file_system_urls);
if (file_system_urls.empty()) { if (file_system_urls.empty()) {
std::move(callback).Run(std::vector<GURL>()); std::move(callback).Run(nullptr);
return; return;
} }
file_manager::util::ConvertToContentUrls(file_system_urls, file_manager::util::ConvertToContentUrls(
std::move(callback)); file_system_urls, base::BindOnce(&SendArcUrls, std::move(callback)));
} }
}; };
......
...@@ -33,6 +33,7 @@ static_library("exo") { ...@@ -33,6 +33,7 @@ static_library("exo") {
"display.h", "display.h",
"drag_drop_operation.cc", "drag_drop_operation.cc",
"drag_drop_operation.h", "drag_drop_operation.h",
"file_helper.h",
"frame_sink_resource_manager.cc", "frame_sink_resource_manager.cc",
"frame_sink_resource_manager.h", "frame_sink_resource_manager.h",
"input_trace.h", "input_trace.h",
......
...@@ -67,7 +67,7 @@ void DataDevice::StartDrag(DataSource* source, ...@@ -67,7 +67,7 @@ void DataDevice::StartDrag(DataSource* source,
Surface* origin, Surface* origin,
Surface* icon, Surface* icon,
ui::mojom::DragEventSource event_source) { ui::mojom::DragEventSource event_source) {
seat_->StartDrag(source, origin, icon, event_source); seat_->StartDrag(file_helper_, source, origin, icon, event_source);
} }
void DataDevice::SetSelection(DataSource* source) { void DataDevice::SetSelection(DataSource* source) {
......
...@@ -40,9 +40,7 @@ constexpr char kTextMimeTypeUtf16[] = "text/plain;charset=utf-16"; ...@@ -40,9 +40,7 @@ constexpr char kTextMimeTypeUtf16[] = "text/plain;charset=utf-16";
constexpr char kTextHtmlMimeTypeUtf8[] = "text/html;charset=utf-8"; constexpr char kTextHtmlMimeTypeUtf8[] = "text/html;charset=utf-8";
constexpr char kTextHtmlMimeTypeUtf16[] = "text/html;charset=utf-16"; constexpr char kTextHtmlMimeTypeUtf16[] = "text/html;charset=utf-16";
constexpr char kTextRtfMimeType[] = "text/rtf"; constexpr char kTextRtfMimeType[] = "text/rtf";
constexpr char kTextUriListMimeType[] = "text/uri-list";
constexpr char kImagePngMimeType[] = "image/png"; constexpr char kImagePngMimeType[] = "image/png";
constexpr char kUriListSeparator[] = "\r\n";
constexpr char kUTF8[] = "utf8"; constexpr char kUTF8[] = "utf8";
constexpr char kUTF16[] = "utf16"; constexpr char kUTF16[] = "utf16";
...@@ -64,28 +62,6 @@ void WriteFileDescriptor(base::ScopedFD fd, ...@@ -64,28 +62,6 @@ void WriteFileDescriptor(base::ScopedFD fd,
std::move(memory))); std::move(memory)));
} }
// Gets a comma-separated list of urls extracted from |data|->file.
bool GetUrlListFromDataFile(FileHelper* file_helper,
aura::Window* target,
const ui::OSExchangeData& data,
base::string16* url_list_string) {
if (!data.HasFile())
return false;
std::vector<ui::FileInfo> files;
if (data.GetFilenames(&files)) {
for (const auto& info : files) {
GURL url;
// TODO(niwa): Need to fill the correct app_id.
if (file_helper->GetUrlFromPath(target, info.path, &url)) {
if (!url_list_string->empty())
*url_list_string += base::UTF8ToUTF16(kUriListSeparator);
*url_list_string += base::UTF8ToUTF16(url.spec());
}
}
}
return !url_list_string->empty();
}
ui::ClipboardFormatType GetClipboardFormatType() { ui::ClipboardFormatType GetClipboardFormatType() {
static const char kFormatString[] = "chromium/x-file-system-files"; static const char kFormatString[] = "chromium/x-file-system-files";
static base::NoDestructor<ui::ClipboardFormatType> format_type( static base::NoDestructor<ui::ClipboardFormatType> format_type(
...@@ -114,16 +90,6 @@ DataOffer::AsyncSendDataCallback AsyncEncodeAsRefCountedString( ...@@ -114,16 +90,6 @@ DataOffer::AsyncSendDataCallback AsyncEncodeAsRefCountedString(
text, charset); text, charset);
} }
DataOffer::AsyncSendDataCallback AsyncSend(
scoped_refptr<base::RefCountedMemory> data) {
return base::BindOnce(
[](scoped_refptr<base::RefCountedMemory> data,
DataOffer::SendDataCallback callback) {
std::move(callback).Run(std::move(data));
},
std::move(data));
}
void ReadTextFromClipboard(const std::string& charset, void ReadTextFromClipboard(const std::string& charset,
DataOffer::SendDataCallback callback) { DataOffer::SendDataCallback callback) {
base::string16 text; base::string16 text;
...@@ -268,39 +234,27 @@ void DataOffer::SetDropData(FileHelper* file_helper, ...@@ -268,39 +234,27 @@ void DataOffer::SetDropData(FileHelper* file_helper,
const ui::OSExchangeData& data) { const ui::OSExchangeData& data) {
DCHECK_EQ(0u, data_callbacks_.size()); DCHECK_EQ(0u, data_callbacks_.size());
std::string filenames_content; const std::string uri_list_mime_type =
// TODO(crbug.com/1144138): If we are dropping this in a VM, we must file_helper->GetMimeTypeForUriList(target);
// translate paths, and share paths at the time when data is received.
if (data.HasFile()) { if (data.HasFile()) {
std::vector<ui::FileInfo> files; std::vector<ui::FileInfo> files;
std::vector<std::string> lines; if (data.GetFilenames(&files)) {
data.GetFilenames(&files); data_callbacks_.emplace(uri_list_mime_type,
for (const auto& file : files) base::BindOnce(&FileHelper::SendFileInfo,
lines.emplace_back(net::FilePathToFileURL(file.path).spec()); base::Unretained(file_helper),
filenames_content = base::JoinString(lines, kUriListSeparator); target, std::move(files)));
data_callbacks_.emplace( delegate_->OnOffer(uri_list_mime_type);
kTextUriListMimeType, return;
AsyncSend(base::RefCountedString::TakeString(&filenames_content))); }
delegate_->OnOffer(kTextUriListMimeType);
}
const std::string uri_list_mime_type = file_helper->GetMimeTypeForUriList();
base::string16 url_list_string;
if (GetUrlListFromDataFile(file_helper, target, data, &url_list_string)) {
data_callbacks_.emplace(
uri_list_mime_type,
AsyncSend(base::RefCountedString16::TakeString(&url_list_string)));
delegate_->OnOffer(uri_list_mime_type);
return;
} }
base::Pickle pickle; base::Pickle pickle;
if (data.GetPickledData(GetClipboardFormatType(), &pickle) && if (data.GetPickledData(GetClipboardFormatType(), &pickle) &&
file_helper->HasUrlsInPickle(pickle)) { file_helper->HasUrlsInPickle(pickle)) {
data_callbacks_.emplace(uri_list_mime_type, data_callbacks_.emplace(
base::BindOnce(&DataOffer::GetUrlsFromPickle, uri_list_mime_type,
weak_ptr_factory_.GetWeakPtr(), base::BindOnce(&FileHelper::SendPickle, base::Unretained(file_helper),
file_helper, target, pickle)); target, pickle));
delegate_->OnOffer(uri_list_mime_type); delegate_->OnOffer(uri_list_mime_type);
return; return;
} }
...@@ -408,28 +362,4 @@ void DataOffer::OnDataReady(const std::string& mime_type, ...@@ -408,28 +362,4 @@ void DataOffer::OnDataReady(const std::string& mime_type,
} }
} }
void DataOffer::GetUrlsFromPickle(FileHelper* file_helper,
aura::Window* target,
const base::Pickle& pickle,
DataOffer::SendDataCallback callback) {
file_helper->GetUrlsFromPickle(
target, pickle,
base::BindOnce(&DataOffer::OnPickledUrlsResolved,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void DataOffer::OnPickledUrlsResolved(DataOffer::SendDataCallback callback,
const std::vector<GURL>& urls) {
base::string16 url_list_string;
for (const GURL& url : urls) {
if (!url.is_valid())
continue;
if (!url_list_string.empty())
url_list_string += base::UTF8ToUTF16(kUriListSeparator);
url_list_string += base::UTF8ToUTF16(url.spec());
}
const auto data = base::RefCountedString16::TakeString(&url_list_string);
std::move(callback).Run(std::move(data));
}
} // namespace exo } // namespace exo
...@@ -316,20 +316,16 @@ TEST_F(DataOfferTest, ReceiveUriListFromPickle_ReceiveBeforeUrlIsResolved) { ...@@ -316,20 +316,16 @@ TEST_F(DataOfferTest, ReceiveUriListFromPickle_ReceiveBeforeUrlIsResolved) {
std::vector<GURL> urls; std::vector<GURL> urls;
urls.push_back( urls.push_back(
GURL("content://org.chromium.arc.chromecontentprovider/path/to/file1")); GURL("content://org.chromium.arc.chromecontentprovider/path/to/file1"));
file_helper.RunUrlsCallback(urls); file_helper.RunSendPickleCallback(urls);
base::string16 result1; std::string result1;
ASSERT_TRUE(ReadString16(std::move(read_pipe1), &result1)); ASSERT_TRUE(ReadString(std::move(read_pipe1), &result1));
EXPECT_EQ( EXPECT_EQ("content://org.chromium.arc.chromecontentprovider/path/to/file1",
base::ASCIIToUTF16( result1);
"content://org.chromium.arc.chromecontentprovider/path/to/file1"), std::string result2;
result1); ASSERT_TRUE(ReadString(std::move(read_pipe2), &result2));
base::string16 result2; EXPECT_EQ("content://org.chromium.arc.chromecontentprovider/path/to/file1",
ASSERT_TRUE(ReadString16(std::move(read_pipe2), &result2)); result2);
EXPECT_EQ(
base::ASCIIToUTF16(
"content://org.chromium.arc.chromecontentprovider/path/to/file1"),
result2);
} }
TEST_F(DataOfferTest, TEST_F(DataOfferTest,
...@@ -359,7 +355,7 @@ TEST_F(DataOfferTest, ...@@ -359,7 +355,7 @@ TEST_F(DataOfferTest,
// Run callback with an empty URL. // Run callback with an empty URL.
std::vector<GURL> urls; std::vector<GURL> urls;
urls.push_back(GURL("")); urls.push_back(GURL(""));
file_helper.RunUrlsCallback(urls); file_helper.RunSendPickleCallback(urls);
base::string16 result; base::string16 result;
ASSERT_TRUE(ReadString16(std::move(read_pipe), &result)); ASSERT_TRUE(ReadString16(std::move(read_pipe), &result));
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/sequenced_task_runner_handle.h"
#include "components/exo/data_offer.h" #include "components/exo/data_offer.h"
#include "components/exo/data_source.h" #include "components/exo/data_source.h"
#include "components/exo/file_helper.h"
#include "components/exo/seat.h" #include "components/exo/seat.h"
#include "components/exo/surface.h" #include "components/exo/surface.h"
#include "components/exo/surface_tree_host.h" #include "components/exo/surface_tree_host.h"
...@@ -143,17 +144,19 @@ class DragDropOperation::IconSurface final : public SurfaceTreeHost, ...@@ -143,17 +144,19 @@ class DragDropOperation::IconSurface final : public SurfaceTreeHost,
}; };
base::WeakPtr<DragDropOperation> DragDropOperation::Create( base::WeakPtr<DragDropOperation> DragDropOperation::Create(
FileHelper* file_helper,
DataSource* source, DataSource* source,
Surface* origin, Surface* origin,
Surface* icon, Surface* icon,
const gfx::PointF& drag_start_point, const gfx::PointF& drag_start_point,
ui::mojom::DragEventSource event_source) { ui::mojom::DragEventSource event_source) {
auto* dnd_op = new DragDropOperation(source, origin, icon, drag_start_point, auto* dnd_op = new DragDropOperation(file_helper, source, origin, icon,
event_source); drag_start_point, event_source);
return dnd_op->weak_ptr_factory_.GetWeakPtr(); return dnd_op->weak_ptr_factory_.GetWeakPtr();
} }
DragDropOperation::DragDropOperation(DataSource* source, DragDropOperation::DragDropOperation(FileHelper* file_helper,
DataSource* source,
Surface* origin, Surface* origin,
Surface* icon, Surface* icon,
const gfx::PointF& drag_start_point, const gfx::PointF& drag_start_point,
...@@ -207,7 +210,8 @@ DragDropOperation::DragDropOperation(DataSource* source, ...@@ -207,7 +210,8 @@ DragDropOperation::DragDropOperation(DataSource* source,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
DataSource::ReadDataCallback(), DataSource::ReadDataCallback(),
base::BindOnce(&DragDropOperation::OnFilenamesRead, base::BindOnce(&DragDropOperation::OnFilenamesRead,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr(), file_helper,
origin->window()),
counter_); counter_);
} }
...@@ -250,24 +254,12 @@ void DragDropOperation::OnHTMLRead(const std::string& mime_type, ...@@ -250,24 +254,12 @@ void DragDropOperation::OnHTMLRead(const std::string& mime_type,
counter_.Run(); counter_.Run();
} }
void DragDropOperation::OnFilenamesRead(const std::string& mime_type, void DragDropOperation::OnFilenamesRead(FileHelper* file_helper,
aura::Window* source,
const std::string& mime_type,
const std::vector<uint8_t>& data) { const std::vector<uint8_t>& data) {
DCHECK(os_exchange_data_); DCHECK(os_exchange_data_);
std::string lines(data.begin(), data.end()); os_exchange_data_->SetFilenames(file_helper->GetFilenames(source, data));
std::vector<ui::FileInfo> filenames;
for (const base::StringPiece& line : base::SplitStringPiece(
lines, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
if (line[0] == '#')
continue;
GURL url(line);
// TODO(crbug.com/1144138): We must translate the path if this was received
// from a VM. E.g. if this was from crostini as
// file:///home/username/file.txt, we translate to
// file:///media/fuse/crostini_<hash>_termina_penguin/file.txt.
filenames.emplace_back(
ui::FileInfo(base::FilePath(url.path()), base::FilePath()));
}
os_exchange_data_->SetFilenames(std::move(filenames));
mime_type_ = mime_type; mime_type_ = mime_type;
counter_.Run(); counter_.Run();
} }
......
...@@ -38,6 +38,7 @@ class OSExchangeData; ...@@ -38,6 +38,7 @@ class OSExchangeData;
} }
namespace exo { namespace exo {
class FileHelper;
class ScopedDataSource; class ScopedDataSource;
class Surface; class Surface;
class ScopedSurface; class ScopedSurface;
...@@ -56,6 +57,7 @@ class DragDropOperation : public DataSourceObserver, ...@@ -56,6 +57,7 @@ class DragDropOperation : public DataSourceObserver,
public: public:
// Create an operation for a drag-drop originating from a wayland app. // Create an operation for a drag-drop originating from a wayland app.
static base::WeakPtr<DragDropOperation> Create( static base::WeakPtr<DragDropOperation> Create(
FileHelper* file_helper,
DataSource* source, DataSource* source,
Surface* origin, Surface* origin,
Surface* icon, Surface* icon,
...@@ -86,7 +88,8 @@ class DragDropOperation : public DataSourceObserver, ...@@ -86,7 +88,8 @@ class DragDropOperation : public DataSourceObserver,
// A private constructor and destructor are used to prevent anyone else from // A private constructor and destructor are used to prevent anyone else from
// attempting to manage the lifetime of a DragDropOperation. // attempting to manage the lifetime of a DragDropOperation.
DragDropOperation(DataSource* source, DragDropOperation(FileHelper* file_helper,
DataSource* source,
Surface* origin, Surface* origin,
Surface* icon, Surface* icon,
const gfx::PointF& drag_start_point, const gfx::PointF& drag_start_point,
...@@ -97,7 +100,9 @@ class DragDropOperation : public DataSourceObserver, ...@@ -97,7 +100,9 @@ class DragDropOperation : public DataSourceObserver,
void OnTextRead(const std::string& mime_type, base::string16 data); void OnTextRead(const std::string& mime_type, base::string16 data);
void OnHTMLRead(const std::string& mime_type, base::string16 data); void OnHTMLRead(const std::string& mime_type, base::string16 data);
void OnFilenamesRead(const std::string& mime_type, void OnFilenamesRead(FileHelper* file_helper,
aura::Window* source,
const std::string& mime_type,
const std::vector<uint8_t>& data); const std::vector<uint8_t>& data);
void ScheduleStartDragDropOperation(); void ScheduleStartDragDropOperation();
......
...@@ -13,8 +13,10 @@ ...@@ -13,8 +13,10 @@
#include "components/exo/buffer.h" #include "components/exo/buffer.h"
#include "components/exo/data_source.h" #include "components/exo/data_source.h"
#include "components/exo/data_source_delegate.h" #include "components/exo/data_source_delegate.h"
#include "components/exo/file_helper.h"
#include "components/exo/surface.h" #include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h" #include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_file_helper.h"
#include "ui/aura/client/drag_drop_client.h" #include "ui/aura/client/drag_drop_client.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
#include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/point_f.h"
...@@ -90,6 +92,8 @@ class DragDropOperationTest : public test::ExoTestBase, ...@@ -90,6 +92,8 @@ class DragDropOperationTest : public test::ExoTestBase,
}; };
TEST_F(DragDropOperationTest, DeleteDuringDragging) { TEST_F(DragDropOperationTest, DeleteDuringDragging) {
TestFileHelper file_helper;
auto delegate = std::make_unique<TestDataSourceDelegate>(); auto delegate = std::make_unique<TestDataSourceDelegate>();
auto data_source = std::make_unique<DataSource>(delegate.get()); auto data_source = std::make_unique<DataSource>(delegate.get());
data_source->Offer(kTextMimeType); data_source->Offer(kTextMimeType);
...@@ -104,7 +108,7 @@ TEST_F(DragDropOperationTest, DeleteDuringDragging) { ...@@ -104,7 +108,7 @@ TEST_F(DragDropOperationTest, DeleteDuringDragging) {
icon_surface->Attach(buffer.get()); icon_surface->Attach(buffer.get());
auto operation = DragDropOperation::Create( auto operation = DragDropOperation::Create(
data_source.get(), origin_surface.get(), icon_surface.get(), &file_helper, data_source.get(), origin_surface.get(), icon_surface.get(),
gfx::PointF(), ui::mojom::DragEventSource::kMouse); gfx::PointF(), ui::mojom::DragEventSource::kMouse);
icon_surface->Commit(); icon_surface->Commit();
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "components/exo/shell_surface.h" #include "components/exo/shell_surface.h"
#include "components/exo/surface.h" #include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h" #include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_file_helper.h"
#include "components/exo/test/exo_test_helper.h" #include "components/exo/test/exo_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/drag_drop_client.h" #include "ui/aura/client/drag_drop_client.h"
...@@ -156,10 +157,11 @@ class ExtendedDragSourceTest : public test::ExoTestBase { ...@@ -156,10 +157,11 @@ class ExtendedDragSourceTest : public test::ExoTestBase {
TEST_F(ExtendedDragSourceTest, DestroySource) { TEST_F(ExtendedDragSourceTest, DestroySource) {
Surface origin; Surface origin;
TestFileHelper file_helper;
// Give |origin| a root window and start DragDropOperation. // Give |origin| a root window and start DragDropOperation.
GetContext()->AddChild(origin.window()); GetContext()->AddChild(origin.window());
seat_->StartDrag(data_source_.get(), &origin, /*icon=*/nullptr, seat_->StartDrag(&file_helper, data_source_.get(), &origin, /*icon=*/nullptr,
ui::mojom::DragEventSource::kMouse); ui::mojom::DragEventSource::kMouse);
// Ensure that destroying the data source invalidates its extended_drag_source // Ensure that destroying the data source invalidates its extended_drag_source
......
...@@ -9,52 +9,57 @@ ...@@ -9,52 +9,57 @@
#include <vector> #include <vector>
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/scoped_refptr.h"
class GURL;
namespace aura { namespace aura {
class Window; class Window;
} }
namespace base { namespace base {
class FilePath;
class Pickle; class Pickle;
} class RefCountedMemory;
} // namespace base
namespace ui {
struct FileInfo;
} // namespace ui
namespace exo { namespace exo {
// Handles file-related translations for wayland clipboard and drag-and-drop.
class FileHelper { class FileHelper {
public: public:
virtual ~FileHelper() {} virtual ~FileHelper() {}
// Returns mime type which is used for list of Uris returned by this // Read filenames from |data| which was provided by source window |source|.
// FileHelper. // Translates paths from source to host format.
virtual std::string GetMimeTypeForUriList() const = 0; virtual std::vector<ui::FileInfo> GetFilenames(
aura::Window* source,
const std::vector<uint8_t>& data) const = 0;
// Converts native file path to URL to be consumed by the target window // Returns the mime type which is used by target window |target| for a list of
// |target|. We don't expose enter file system to a container directly. // file path URIs.
// Instead we mount specific directory in the containers' namespace. Thus we virtual std::string GetMimeTypeForUriList(aura::Window* target) const = 0;
// need to convert native path to file URL which points mount point in
// containers. The conversion should be container specific, now we only have // Sends the given file list |files| to target window |target| window.
// ARC container though. // Translates paths from host format to the target and performs any required
virtual bool GetUrlFromPath(aura::Window* target, // file sharing for VMs.
const base::FilePath& path, using SendDataCallback =
GURL* out) = 0; base::OnceCallback<void(scoped_refptr<base::RefCountedMemory>)>;
virtual void SendFileInfo(aura::Window* target,
const std::vector<ui::FileInfo>& files,
SendDataCallback callback) const = 0;
// Takes in |pickle| constructed by the web contents view and returns true if // Takes in |pickle| constructed by the web contents view and returns true if
// it contains any valid filesystem URLs. // it contains any valid filesystem URLs.
virtual bool HasUrlsInPickle(const base::Pickle& pickle) = 0; virtual bool HasUrlsInPickle(const base::Pickle& pickle) const = 0;
using UrlsFromPickleCallback = // Takes in |pickle| constructed by the web contents view containing
base::OnceCallback<void(const std::vector<GURL>& urls)>; // filesystem URLs. Provides translations for the specified target window
// |target| and performs any required file sharing for VMs..
// Takes in |pickle| constructed by the web contents view, reads filesystem virtual void SendPickle(aura::Window* target,
// URLs from it and converts the URLs to something that applications const base::Pickle& pickle,
// represented by |target| can understand and consume. e.g. content:// URI SendDataCallback callback) = 0;
// for Android apps.
virtual void GetUrlsFromPickle(aura::Window* target,
const base::Pickle& pickle,
UrlsFromPickleCallback callback) = 0;
}; };
} // namespace exo } // namespace exo
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "components/exo/sub_surface.h" #include "components/exo/sub_surface.h"
#include "components/exo/surface.h" #include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h" #include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_file_helper.h"
#include "components/exo/test/exo_test_helper.h" #include "components/exo/test/exo_test_helper.h"
#include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/service/surfaces/surface.h" #include "components/viz/service/surfaces/surface.h"
...@@ -941,6 +942,7 @@ TEST_F(PointerTest, DragDropAbort) { ...@@ -941,6 +942,7 @@ TEST_F(PointerTest, DragDropAbort) {
TestDataSourceDelegate data_source_delegate; TestDataSourceDelegate data_source_delegate;
DataSource source(&data_source_delegate); DataSource source(&data_source_delegate);
Surface origin, icon; Surface origin, icon;
TestFileHelper file_helper;
// Make origin into a real window so the pointer can click it // Make origin into a real window so the pointer can click it
ShellSurface shell_surface(&origin); ShellSurface shell_surface(&origin);
...@@ -956,7 +958,8 @@ TEST_F(PointerTest, DragDropAbort) { ...@@ -956,7 +958,8 @@ TEST_F(PointerTest, DragDropAbort) {
EXPECT_CALL(pointer_delegate, OnPointerEnter(&origin, gfx::PointF(), 0)); EXPECT_CALL(pointer_delegate, OnPointerEnter(&origin, gfx::PointF(), 0));
generator.MoveMouseTo(origin.window()->GetBoundsInScreen().origin()); generator.MoveMouseTo(origin.window()->GetBoundsInScreen().origin());
seat.StartDrag(&source, &origin, &icon, ui::mojom::DragEventSource::kMouse); seat.StartDrag(&file_helper, &source, &origin, &icon,
ui::mojom::DragEventSource::kMouse);
EXPECT_TRUE(seat.get_drag_drop_operation_for_testing()); EXPECT_TRUE(seat.get_drag_drop_operation_for_testing());
EXPECT_CALL(pointer_delegate, OnPointerButton).Times(2); EXPECT_CALL(pointer_delegate, OnPointerButton).Times(2);
......
...@@ -105,13 +105,14 @@ Surface* Seat::GetFocusedSurface() { ...@@ -105,13 +105,14 @@ Surface* Seat::GetFocusedSurface() {
return GetEffectiveFocus(WMHelper::GetInstance()->GetFocusedWindow()); return GetEffectiveFocus(WMHelper::GetInstance()->GetFocusedWindow());
} }
void Seat::StartDrag(DataSource* source, void Seat::StartDrag(FileHelper* file_helper,
DataSource* source,
Surface* origin, Surface* origin,
Surface* icon, Surface* icon,
ui::mojom::DragEventSource event_source) { ui::mojom::DragEventSource event_source) {
// DragDropOperation manages its own lifetime. // DragDropOperation manages its own lifetime.
drag_drop_operation_ = DragDropOperation::Create( drag_drop_operation_ = DragDropOperation::Create(
source, origin, icon, last_pointer_location_, event_source); file_helper, source, origin, icon, last_pointer_location_, event_source);
} }
void Seat::SetLastPointerLocation(const gfx::PointF& last_pointer_location) { void Seat::SetLastPointerLocation(const gfx::PointF& last_pointer_location) {
......
...@@ -31,6 +31,7 @@ class KeyEvent; ...@@ -31,6 +31,7 @@ class KeyEvent;
namespace exo { namespace exo {
class DragDropOperation; class DragDropOperation;
class FileHelper;
class ScopedDataSource; class ScopedDataSource;
class SeatObserver; class SeatObserver;
class Surface; class Surface;
...@@ -80,7 +81,8 @@ class Seat : public aura::client::FocusChangeObserver, ...@@ -80,7 +81,8 @@ class Seat : public aura::client::FocusChangeObserver,
// Sets clipboard data from |source|. // Sets clipboard data from |source|.
void SetSelection(DataSource* source); void SetSelection(DataSource* source);
void StartDrag(DataSource* source, void StartDrag(FileHelper* file_helper,
DataSource* source,
Surface* origin, Surface* origin,
Surface* icon, Surface* icon,
ui::mojom::DragEventSource event_source); ui::mojom::DragEventSource event_source);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "components/exo/seat_observer.h" #include "components/exo/seat_observer.h"
#include "components/exo/surface.h" #include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h" #include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_file_helper.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h" #include "ui/base/clipboard/scoped_clipboard_writer.h"
...@@ -488,11 +489,13 @@ TEST_F(SeatTest, DragDropAbort) { ...@@ -488,11 +489,13 @@ TEST_F(SeatTest, DragDropAbort) {
TestDataSourceDelegate delegate; TestDataSourceDelegate delegate;
DataSource source(&delegate); DataSource source(&delegate);
Surface origin, icon; Surface origin, icon;
TestFileHelper file_helper;
// Give origin a root window for DragDropOperation. // Give origin a root window for DragDropOperation.
GetContext()->AddChild(origin.window()); GetContext()->AddChild(origin.window());
seat.StartDrag(&source, &origin, &icon, ui::mojom::DragEventSource::kMouse); seat.StartDrag(&file_helper, &source, &origin, &icon,
ui::mojom::DragEventSource::kMouse);
EXPECT_TRUE(seat.get_drag_drop_operation_for_testing()); EXPECT_TRUE(seat.get_drag_drop_operation_for_testing());
seat.AbortPendingDragOperation(); seat.AbortPendingDragOperation();
EXPECT_FALSE(seat.get_drag_drop_operation_for_testing()); EXPECT_FALSE(seat.get_drag_drop_operation_for_testing());
......
...@@ -6,9 +6,15 @@ ...@@ -6,9 +6,15 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector>
#include "base/callback.h" #include "base/callback.h"
#include "base/files/file_path.h" #include "base/memory/ref_counted_memory.h"
#include "base/pickle.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "net/base/filename_util.h"
#include "ui/base/dragdrop/file_info/file_info.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace exo { namespace exo {
...@@ -17,29 +23,53 @@ TestFileHelper::TestFileHelper() = default; ...@@ -17,29 +23,53 @@ TestFileHelper::TestFileHelper() = default;
TestFileHelper::~TestFileHelper() = default; TestFileHelper::~TestFileHelper() = default;
std::string TestFileHelper::GetMimeTypeForUriList() const { std::vector<ui::FileInfo> TestFileHelper::GetFilenames(
aura::Window* source,
const std::vector<uint8_t>& data) const {
std::string lines(data.begin(), data.end());
std::vector<ui::FileInfo> filenames;
for (const base::StringPiece& line : base::SplitStringPiece(
lines, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
base::FilePath path;
if (net::FileURLToFilePath(GURL(line), &path))
filenames.emplace_back(ui::FileInfo(path, base::FilePath()));
}
return filenames;
}
std::string TestFileHelper::GetMimeTypeForUriList(aura::Window* target) const {
return "text/uri-list"; return "text/uri-list";
} }
bool TestFileHelper::GetUrlFromPath(aura::Window* target, void TestFileHelper::SendFileInfo(aura::Window* target,
const base::FilePath& path, const std::vector<ui::FileInfo>& files,
GURL* out) { SendDataCallback callback) const {
*out = GURL("file://" + path.value()); std::vector<std::string> lines;
return true; for (const auto& file : files) {
lines.emplace_back("file://" + file.path.value());
}
std::string result = base::JoinString(lines, "\r\n");
std::move(callback).Run(base::RefCountedString::TakeString(&result));
} }
bool TestFileHelper::HasUrlsInPickle(const base::Pickle& pickle) { bool TestFileHelper::HasUrlsInPickle(const base::Pickle& pickle) const {
return true; return true;
} }
void TestFileHelper::GetUrlsFromPickle(aura::Window* target, void TestFileHelper::SendPickle(aura::Window* target,
const base::Pickle& pickle, const base::Pickle& pickle,
UrlsFromPickleCallback callback) { SendDataCallback callback) {
urls_callback_ = std::move(callback); send_pickle_callback_ = std::move(callback);
} }
void TestFileHelper::RunUrlsCallback(std::vector<GURL> urls) { void TestFileHelper::RunSendPickleCallback(std::vector<GURL> urls) {
std::move(urls_callback_).Run(urls); std::vector<std::string> lines;
for (const auto& url : urls) {
lines.emplace_back(url.spec());
}
std::string result = base::JoinString(lines, "\r\n");
std::move(send_pickle_callback_)
.Run(base::RefCountedString::TakeString(&result));
} }
} // namespace exo } // namespace exo
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include "components/exo/file_helper.h" #include "components/exo/file_helper.h"
class GURL;
namespace exo { namespace exo {
class TestFileHelper : public FileHelper { class TestFileHelper : public FileHelper {
...@@ -17,19 +19,22 @@ class TestFileHelper : public FileHelper { ...@@ -17,19 +19,22 @@ class TestFileHelper : public FileHelper {
~TestFileHelper() override; ~TestFileHelper() override;
// FileHelper: // FileHelper:
std::string GetMimeTypeForUriList() const override; std::vector<ui::FileInfo> GetFilenames(
bool GetUrlFromPath(aura::Window* target, aura::Window* source,
const base::FilePath& path, const std::vector<uint8_t>& data) const override;
GURL* out) override; std::string GetMimeTypeForUriList(aura::Window* target) const override;
bool HasUrlsInPickle(const base::Pickle& pickle) override; void SendFileInfo(aura::Window* target,
void GetUrlsFromPickle(aura::Window* target, const std::vector<ui::FileInfo>& files,
const base::Pickle& pickle, SendDataCallback callback) const override;
UrlsFromPickleCallback callback) override; bool HasUrlsInPickle(const base::Pickle& pickle) const override;
void SendPickle(aura::Window* target,
void RunUrlsCallback(std::vector<GURL> urls); const base::Pickle& pickle,
SendDataCallback callback) override;
void RunSendPickleCallback(std::vector<GURL> urls);
private: private:
UrlsFromPickleCallback urls_callback_; SendDataCallback send_pickle_callback_;
}; };
} // namespace exo } // namespace exo
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "components/exo/shell_surface.h" #include "components/exo/shell_surface.h"
#include "components/exo/surface.h" #include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h" #include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_file_helper.h"
#include "components/exo/test/exo_test_helper.h" #include "components/exo/test/exo_test_helper.h"
#include "components/exo/touch_delegate.h" #include "components/exo/touch_delegate.h"
#include "components/exo/touch_stylus_delegate.h" #include "components/exo/touch_stylus_delegate.h"
...@@ -506,6 +507,7 @@ TEST_F(TouchTest, DragDropAbort) { ...@@ -506,6 +507,7 @@ TEST_F(TouchTest, DragDropAbort) {
TestDataSourceDelegate data_source_delegate; TestDataSourceDelegate data_source_delegate;
DataSource source(&data_source_delegate); DataSource source(&data_source_delegate);
Surface origin, icon; Surface origin, icon;
TestFileHelper file_helper;
// Make origin into a real window so the touch can click it // Make origin into a real window so the touch can click it
ShellSurface shell_surface(&origin); ShellSurface shell_surface(&origin);
...@@ -520,7 +522,8 @@ TEST_F(TouchTest, DragDropAbort) { ...@@ -520,7 +522,8 @@ TEST_F(TouchTest, DragDropAbort) {
EXPECT_CALL(touch_delegate, OnTouchFrame()).Times(2); EXPECT_CALL(touch_delegate, OnTouchFrame()).Times(2);
generator.MoveTouch(origin.window()->GetBoundsInScreen().origin()); generator.MoveTouch(origin.window()->GetBoundsInScreen().origin());
seat.StartDrag(&source, &origin, &icon, ui::mojom::DragEventSource::kMouse); seat.StartDrag(&file_helper, &source, &origin, &icon,
ui::mojom::DragEventSource::kMouse);
EXPECT_TRUE(seat.get_drag_drop_operation_for_testing()); EXPECT_TRUE(seat.get_drag_drop_operation_for_testing());
EXPECT_CALL(touch_delegate, OnTouchDown).Times(1); EXPECT_CALL(touch_delegate, OnTouchDown).Times(1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment