Added parallel import (#15674)
* Added opportunity to make multiple import requests in parallel
This commit is contained in:
@@ -199,4 +199,13 @@ void BraveExternalProcessImporterHost::SetInstallExtensionCallbackForTesting(
|
||||
install_extension_callback_for_testing_ = std::move(callback);
|
||||
}
|
||||
|
||||
void BraveExternalProcessImporterHost::NotifyImportEndedForTesting() {
|
||||
ExternalProcessImporterHost::NotifyImportEnded();
|
||||
}
|
||||
|
||||
importer::ImporterProgressObserver*
|
||||
BraveExternalProcessImporterHost::GetObserverForTesting() {
|
||||
return observer_;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,6 +30,9 @@ class BraveExternalProcessImporterHost : public ExternalProcessImporterHost {
|
||||
friend class ExternalProcessImporterHost;
|
||||
friend class BraveExternalProcessImporterHostUnitTest;
|
||||
|
||||
FRIEND_TEST_ALL_PREFIXES(BraveImporterObserverUnitTest, ImportEvents);
|
||||
FRIEND_TEST_ALL_PREFIXES(BraveImporterObserverUnitTest, DestroyObserverEarly);
|
||||
|
||||
~BraveExternalProcessImporterHost() override;
|
||||
void OnExtensionInstalled(const std::string& extension_id,
|
||||
bool success,
|
||||
@@ -42,6 +45,8 @@ class BraveExternalProcessImporterHost : public ExternalProcessImporterHost {
|
||||
void DoNotLaunchImportForTesting();
|
||||
void SetInstallExtensionCallbackForTesting(MockedInstallCallback callback);
|
||||
void SetSettingsRemovedCallbackForTesting(base::RepeatingClosure callback);
|
||||
void NotifyImportEndedForTesting();
|
||||
importer::ImporterProgressObserver* GetObserverForTesting();
|
||||
|
||||
// ExternalProcessImporterHost overrides:
|
||||
void NotifyImportEnded() override;
|
||||
|
||||
+9
-3
@@ -139,7 +139,10 @@ source_set("ui") {
|
||||
"webui/settings/brave_adblock_handler.h",
|
||||
"webui/settings/brave_appearance_handler.cc",
|
||||
"webui/settings/brave_appearance_handler.h",
|
||||
"webui/settings/brave_import_data_handler.cc",
|
||||
"webui/settings/brave_import_data_handler.h",
|
||||
"webui/settings/brave_importer_observer.cc",
|
||||
"webui/settings/brave_importer_observer.h",
|
||||
"webui/settings/brave_privacy_handler.cc",
|
||||
"webui/settings/brave_privacy_handler.h",
|
||||
"webui/settings/brave_search_engines_handler.cc",
|
||||
@@ -152,6 +155,8 @@ source_set("ui") {
|
||||
"webui/settings/brave_wallet_handler.h",
|
||||
"webui/settings/default_brave_shields_handler.cc",
|
||||
"webui/settings/default_brave_shields_handler.h",
|
||||
"webui/settings/import_feature.cc",
|
||||
"webui/settings/import_feature.h",
|
||||
"webui/speedreader/speedreader_panel_data_handler_impl.cc",
|
||||
"webui/speedreader/speedreader_panel_data_handler_impl.h",
|
||||
"webui/speedreader/speedreader_panel_handler_impl.cc",
|
||||
@@ -168,9 +173,10 @@ source_set("ui") {
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
sources += [ "webui/settings/brave_import_data_handler_mac.mm" ]
|
||||
} else {
|
||||
sources += [ "webui/settings/brave_import_data_handler.cc" ]
|
||||
sources += [
|
||||
"webui/settings/brave_full_disk_access_confirm_dialog_delegate.h",
|
||||
"webui/settings/brave_full_disk_access_confirm_dialog_delegate_mac.mm",
|
||||
]
|
||||
}
|
||||
|
||||
if (enable_sparkle) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Copyright (c) 2022 The Brave Authors. All rights reserved.
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
source_set("unittests") {
|
||||
if (!is_android) {
|
||||
testonly = true
|
||||
|
||||
sources = [ "brave_importer_observer_unittest.cc" ]
|
||||
|
||||
deps = [
|
||||
"//base/test:test_support",
|
||||
"//brave/browser/ui",
|
||||
"//chrome/browser",
|
||||
"//chrome/browser/ui",
|
||||
"//content/test:test_support",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_FULL_DISK_ACCESS_CONFIRM_DIALOG_DELEGATE_H_
|
||||
#define BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_FULL_DISK_ACCESS_CONFIRM_DIALOG_DELEGATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
|
||||
|
||||
namespace content {
|
||||
class WebContents;
|
||||
} // namespace content
|
||||
|
||||
class Browser;
|
||||
|
||||
class FullDiskAccessConfirmDialogDelegate
|
||||
: public TabModalConfirmDialogDelegate {
|
||||
public:
|
||||
FullDiskAccessConfirmDialogDelegate(content::WebContents* web_contents,
|
||||
Browser* browser);
|
||||
~FullDiskAccessConfirmDialogDelegate() override;
|
||||
|
||||
FullDiskAccessConfirmDialogDelegate(
|
||||
const FullDiskAccessConfirmDialogDelegate&) = delete;
|
||||
FullDiskAccessConfirmDialogDelegate& operator=(
|
||||
const FullDiskAccessConfirmDialogDelegate&) = delete;
|
||||
|
||||
private:
|
||||
// TabModalConfirmDialogDelegate overrides:
|
||||
std::u16string GetTitle() override;
|
||||
std::u16string GetDialogMessage() override;
|
||||
std::u16string GetLinkText() const override;
|
||||
std::u16string GetAcceptButtonTitle() override;
|
||||
void OnAccepted() override;
|
||||
void OnLinkClicked(WindowOpenDisposition disposition) override;
|
||||
|
||||
raw_ptr<Browser> browser_;
|
||||
};
|
||||
|
||||
#endif // BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_FULL_DISK_ACCESS_CONFIRM_DIALOG_DELEGATE_H_
|
||||
@@ -0,0 +1,66 @@
|
||||
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "brave/browser/ui/webui/settings/brave_full_disk_access_confirm_dialog_delegate.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/values.h"
|
||||
#include "brave/components/constants/url_constants.h"
|
||||
#include "brave/components/l10n/common/localization_util.h"
|
||||
#include "chrome/browser/importer/external_process_importer_host.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/ui/browser_tabstrip.h"
|
||||
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
|
||||
#include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
|
||||
#include "chrome/common/importer/importer_data_types.h"
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "content/public/browser/web_ui.h"
|
||||
#include "ui/base/ui_base_types.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
FullDiskAccessConfirmDialogDelegate::FullDiskAccessConfirmDialogDelegate(
|
||||
content::WebContents* web_contents,
|
||||
Browser* browser)
|
||||
: TabModalConfirmDialogDelegate(web_contents), browser_(browser) {}
|
||||
|
||||
FullDiskAccessConfirmDialogDelegate::~FullDiskAccessConfirmDialogDelegate() =
|
||||
default;
|
||||
|
||||
std::u16string FullDiskAccessConfirmDialogDelegate::GetTitle() {
|
||||
return brave_l10n::GetLocalizedResourceUTF16String(
|
||||
IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_TITLE);
|
||||
}
|
||||
|
||||
std::u16string FullDiskAccessConfirmDialogDelegate::GetDialogMessage() {
|
||||
return brave_l10n::GetLocalizedResourceUTF16String(
|
||||
IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_MESSAGE);
|
||||
}
|
||||
|
||||
std::u16string FullDiskAccessConfirmDialogDelegate::GetLinkText() const {
|
||||
return brave_l10n::GetLocalizedResourceUTF16String(
|
||||
IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_LINK_TEXT);
|
||||
}
|
||||
|
||||
std::u16string FullDiskAccessConfirmDialogDelegate::GetAcceptButtonTitle() {
|
||||
return brave_l10n::GetLocalizedResourceUTF16String(
|
||||
IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_OPEN_PREFS_BUTTON_TEXT);
|
||||
}
|
||||
|
||||
void FullDiskAccessConfirmDialogDelegate::OnAccepted() {
|
||||
[[NSWorkspace sharedWorkspace]
|
||||
openURL:[NSURL URLWithString:
|
||||
@"x-apple.systempreferences:com.apple.preference."
|
||||
@"security?Privacy_AllFiles"]]; // NOLINT
|
||||
}
|
||||
|
||||
void FullDiskAccessConfirmDialogDelegate::OnLinkClicked(
|
||||
WindowOpenDisposition disposition) {
|
||||
const int target_index = browser_->tab_strip_model()->active_index() + 1;
|
||||
// Add import help tab right after current settings tab.
|
||||
chrome::AddTabAt(browser_, GURL(kImportDataHelpURL), target_index,
|
||||
true /* foreground */);
|
||||
}
|
||||
@@ -5,9 +5,181 @@
|
||||
|
||||
#include "brave/browser/ui/webui/settings/brave_import_data_handler.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "brave/browser/ui/webui/settings/import_feature.h"
|
||||
#include "chrome/browser/importer/external_process_importer_host.h"
|
||||
#include "chrome/browser/importer/profile_writer.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/mac/foundation_util.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "brave/browser/ui/webui/settings/brave_full_disk_access_confirm_dialog_delegate.h"
|
||||
#include "chrome/browser/ui/browser_finder.h"
|
||||
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
|
||||
namespace {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
bool HasProperDiskAccessPermission(uint16_t imported_items) {
|
||||
DCHECK(imported_items);
|
||||
|
||||
const base::FilePath& library_dir = base::mac::GetUserLibraryPath();
|
||||
const base::FilePath safari_dir = library_dir.Append("Safari");
|
||||
|
||||
if (imported_items & importer::FAVORITES) {
|
||||
const base::FilePath bookmarks_path = safari_dir.Append("Bookmarks.plist");
|
||||
if (!PathIsWritable(bookmarks_path)) {
|
||||
LOG(ERROR) << __func__ << " " << bookmarks_path << " is not accessible."
|
||||
<< " Please check full disk access permission.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (imported_items & importer::HISTORY) {
|
||||
const base::FilePath history_path = safari_dir.Append("History.plist");
|
||||
if (!PathIsWritable(history_path)) {
|
||||
LOG(ERROR) << __func__ << " " << history_path << " is not accessible."
|
||||
<< " Please check full disk access permission.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
} // namespace
|
||||
|
||||
namespace settings {
|
||||
|
||||
BraveImportDataHandler::BraveImportDataHandler() = default;
|
||||
BraveImportDataHandler::~BraveImportDataHandler() = default;
|
||||
|
||||
void BraveImportDataHandler::StartImport(
|
||||
const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items) {
|
||||
if (!imported_items)
|
||||
return;
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
CheckDiskAccess(source_profile, imported_items);
|
||||
#else
|
||||
StartImportImpl(source_profile, imported_items);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BraveImportDataHandler::StartImportImpl(
|
||||
const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items) {
|
||||
// Temporary flag to keep old way until
|
||||
// https://github.com/brave/brave-core/pull/15637 landed.
|
||||
// Should be removed in that PR.
|
||||
if (!IsParallelImportEnabled()) {
|
||||
ImportDataHandler::StartImport(source_profile, imported_items);
|
||||
return;
|
||||
}
|
||||
// If another import is already ongoing, let it finish silently.
|
||||
if (import_observers_.count(source_profile.source_path))
|
||||
import_observers_.erase(source_profile.source_path);
|
||||
|
||||
// Using weak pointers because it destroys itself when finshed.
|
||||
auto* importer_host = new ExternalProcessImporterHost();
|
||||
import_observers_[source_profile.source_path] =
|
||||
std::make_unique<BraveImporterObserver>(
|
||||
importer_host, source_profile, imported_items,
|
||||
base::BindRepeating(&BraveImportDataHandler::NotifyImportProgress,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
Profile* profile = Profile::FromWebUI(web_ui());
|
||||
importer_host->StartImportSettings(source_profile, profile, imported_items,
|
||||
new ProfileWriter(profile));
|
||||
}
|
||||
|
||||
void BraveImportDataHandler::NotifyImportProgress(
|
||||
const importer::SourceProfile& source_profile,
|
||||
const base::Value& info) {
|
||||
FireWebUIListener("brave-import-data-status-changed", info);
|
||||
const std::string* event = info.FindStringKey("event");
|
||||
if (event && *event == "ImportEnded") {
|
||||
content::GetUIThreadTaskRunner({})->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&BraveImportDataHandler::OnImportEnded,
|
||||
weak_factory_.GetWeakPtr(), source_profile.source_path));
|
||||
}
|
||||
}
|
||||
|
||||
void BraveImportDataHandler::OnImportEnded(const base::FilePath& source_path) {
|
||||
import_observers_.erase(source_path);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
void BraveImportDataHandler::CheckDiskAccess(
|
||||
const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
guide_dialog_is_requested_ = false;
|
||||
|
||||
if (!imported_items)
|
||||
return;
|
||||
|
||||
if (source_profile.importer_type == importer::TYPE_SAFARI) {
|
||||
// Start import if Brave has full disk access permission.
|
||||
// If not, show dialog that has infos about that permission.
|
||||
base::ThreadPool::PostTaskAndReplyWithResult(
|
||||
FROM_HERE, {base::MayBlock()},
|
||||
base::BindOnce(&HasProperDiskAccessPermission, imported_items),
|
||||
base::BindOnce(&BraveImportDataHandler::OnGetDiskAccessPermission,
|
||||
weak_factory_.GetWeakPtr(), source_profile,
|
||||
imported_items));
|
||||
return;
|
||||
}
|
||||
|
||||
StartImportImpl(source_profile, imported_items);
|
||||
}
|
||||
|
||||
void BraveImportDataHandler::OnGetDiskAccessPermission(
|
||||
const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items,
|
||||
bool allowed) {
|
||||
if (!allowed) {
|
||||
// Notify to webui to finish import process and launch tab modal dialog
|
||||
// to guide full disk access information to users.
|
||||
// Guide dialog will be opened after import dialog is closed.
|
||||
FireWebUIListener("import-data-status-changed", base::Value("failed"));
|
||||
if (IsParallelImportEnabled()) {
|
||||
import_observers_[source_profile.source_path]->ImportEnded();
|
||||
}
|
||||
// Observing web_contents is started here to know the closing timing of
|
||||
// import dialog.
|
||||
Observe(web_ui()->GetWebContents());
|
||||
|
||||
guide_dialog_is_requested_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
StartImportImpl(source_profile, imported_items);
|
||||
}
|
||||
|
||||
void BraveImportDataHandler::DidStopLoading() {
|
||||
Observe(nullptr);
|
||||
|
||||
if (!guide_dialog_is_requested_)
|
||||
return;
|
||||
|
||||
guide_dialog_is_requested_ = false;
|
||||
|
||||
auto* web_contents = web_ui()->GetWebContents();
|
||||
TabModalConfirmDialog::Create(
|
||||
std::make_unique<FullDiskAccessConfirmDialogDelegate>(
|
||||
web_contents, chrome::FindBrowserWithWebContents(web_contents)),
|
||||
web_contents);
|
||||
}
|
||||
#endif
|
||||
} // namespace settings
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
#ifndef BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_IMPORT_DATA_HANDLER_H_
|
||||
#define BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_IMPORT_DATA_HANDLER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "brave/browser/ui/webui/settings/brave_importer_observer.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/ui/webui/settings/import_data_handler.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
@@ -25,8 +29,6 @@ namespace settings {
|
||||
// new navigation start and tab is newly loaded for closing webui import dialog.
|
||||
// The reason why native tab modal dialog is used here is to avoid modifying
|
||||
// upstream import html/js source code.
|
||||
|
||||
// NOTE: This is no-op class for other platforms except macOS.
|
||||
class BraveImportDataHandler : public ImportDataHandler,
|
||||
content::WebContentsObserver {
|
||||
public:
|
||||
@@ -37,11 +39,18 @@ class BraveImportDataHandler : public ImportDataHandler,
|
||||
BraveImportDataHandler& operator=(const BraveImportDataHandler&) = delete;
|
||||
|
||||
private:
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
// ImportDataHandler overrides:
|
||||
void StartImport(const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items) override;
|
||||
|
||||
void StartImportImpl(const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items);
|
||||
void NotifyImportProgress(const importer::SourceProfile& source_profile,
|
||||
const base::Value& info);
|
||||
void OnImportEnded(const base::FilePath& source_path);
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
void CheckDiskAccess(const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items);
|
||||
void OnGetDiskAccessPermission(const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items,
|
||||
bool allowed);
|
||||
@@ -50,9 +59,11 @@ class BraveImportDataHandler : public ImportDataHandler,
|
||||
void DidStopLoading() override;
|
||||
|
||||
bool guide_dialog_is_requested_ = false;
|
||||
|
||||
base::WeakPtrFactory<BraveImportDataHandler> weak_factory_;
|
||||
#endif
|
||||
|
||||
std::unordered_map<base::FilePath, std::unique_ptr<BraveImporterObserver>>
|
||||
import_observers_;
|
||||
base::WeakPtrFactory<BraveImportDataHandler> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace settings
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
/* Copyright (c) 2020 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "brave/browser/ui/webui/settings/brave_import_data_handler.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/mac/foundation_util.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "base/values.h"
|
||||
#include "brave/components/constants/url_constants.h"
|
||||
#include "brave/components/l10n/common/localization_util.h"
|
||||
#include "chrome/browser/importer/external_process_importer_host.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/ui/browser_finder.h"
|
||||
#include "chrome/browser/ui/browser_tabstrip.h"
|
||||
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
|
||||
#include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
|
||||
#include "chrome/common/importer/importer_data_types.h"
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/web_ui.h"
|
||||
#include "ui/base/ui_base_types.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
class FullDiskAccessConfirmDialogDelegate
|
||||
: public TabModalConfirmDialogDelegate {
|
||||
public:
|
||||
FullDiskAccessConfirmDialogDelegate(content::WebContents* web_contents,
|
||||
Browser* browser);
|
||||
~FullDiskAccessConfirmDialogDelegate() override;
|
||||
|
||||
FullDiskAccessConfirmDialogDelegate(
|
||||
const FullDiskAccessConfirmDialogDelegate&) = delete;
|
||||
FullDiskAccessConfirmDialogDelegate& operator=(
|
||||
const FullDiskAccessConfirmDialogDelegate&) = delete;
|
||||
|
||||
private:
|
||||
// TabModalConfirmDialogDelegate overrides:
|
||||
std::u16string GetTitle() override;
|
||||
std::u16string GetDialogMessage() override;
|
||||
std::u16string GetLinkText() const override;
|
||||
std::u16string GetAcceptButtonTitle() override;
|
||||
void OnAccepted() override;
|
||||
void OnLinkClicked(WindowOpenDisposition disposition) override;
|
||||
|
||||
Browser* browser_;
|
||||
};
|
||||
|
||||
FullDiskAccessConfirmDialogDelegate::FullDiskAccessConfirmDialogDelegate(
|
||||
content::WebContents* web_contents,
|
||||
Browser* browser)
|
||||
: TabModalConfirmDialogDelegate(web_contents),
|
||||
browser_(browser) {}
|
||||
|
||||
FullDiskAccessConfirmDialogDelegate::
|
||||
~FullDiskAccessConfirmDialogDelegate() = default;
|
||||
|
||||
std::u16string FullDiskAccessConfirmDialogDelegate::GetTitle() {
|
||||
return brave_l10n::GetLocalizedResourceUTF16String(
|
||||
IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_TITLE);
|
||||
}
|
||||
|
||||
std::u16string FullDiskAccessConfirmDialogDelegate::GetDialogMessage() {
|
||||
return brave_l10n::GetLocalizedResourceUTF16String(
|
||||
IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_MESSAGE);
|
||||
}
|
||||
|
||||
std::u16string FullDiskAccessConfirmDialogDelegate::GetLinkText() const {
|
||||
return brave_l10n::GetLocalizedResourceUTF16String(
|
||||
IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_LINK_TEXT);
|
||||
}
|
||||
|
||||
std::u16string FullDiskAccessConfirmDialogDelegate::GetAcceptButtonTitle() {
|
||||
return brave_l10n::GetLocalizedResourceUTF16String(
|
||||
IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_OPEN_PREFS_BUTTON_TEXT);
|
||||
}
|
||||
|
||||
void FullDiskAccessConfirmDialogDelegate::OnAccepted() {
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:
|
||||
@"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"]]; // NOLINT
|
||||
}
|
||||
|
||||
void FullDiskAccessConfirmDialogDelegate::OnLinkClicked(
|
||||
WindowOpenDisposition disposition) {
|
||||
const int target_index =
|
||||
browser_->tab_strip_model()->active_index() + 1;
|
||||
// Add import help tab right after current settings tab.
|
||||
chrome::AddTabAt(browser_, GURL(kImportDataHelpURL),
|
||||
target_index, true /* foreground */);
|
||||
}
|
||||
|
||||
bool HasProperDiskAccessPermission(uint16_t imported_items) {
|
||||
DCHECK(imported_items);
|
||||
|
||||
const base::FilePath& library_dir = base::mac::GetUserLibraryPath();
|
||||
const base::FilePath safari_dir = library_dir.Append("Safari");
|
||||
|
||||
if (imported_items & importer::FAVORITES) {
|
||||
const base::FilePath bookmarks_path = safari_dir.Append("Bookmarks.plist");
|
||||
if(!PathIsWritable(bookmarks_path)) {
|
||||
LOG(ERROR) << __func__ << " " << bookmarks_path << " is not accessible."
|
||||
<< " Please check full disk access permission.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (imported_items & importer::HISTORY) {
|
||||
const base::FilePath history_path = safari_dir.Append("History.plist");
|
||||
if(!PathIsWritable(history_path)) {
|
||||
LOG(ERROR) << __func__ << " " << history_path << " is not accessible."
|
||||
<< " Please check full disk access permission.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace settings {
|
||||
|
||||
BraveImportDataHandler::BraveImportDataHandler() : weak_factory_(this) {}
|
||||
BraveImportDataHandler::~BraveImportDataHandler() = default;
|
||||
|
||||
void BraveImportDataHandler::StartImport(
|
||||
const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
guide_dialog_is_requested_ = false;
|
||||
|
||||
if (!imported_items)
|
||||
return;
|
||||
|
||||
if (source_profile.importer_type == importer::TYPE_SAFARI) {
|
||||
// Start import if Brave has full disk access permission.
|
||||
// If not, show dialog that has infos about that permission.
|
||||
base::ThreadPool::PostTaskAndReplyWithResult(
|
||||
FROM_HERE, {base::MayBlock()},
|
||||
base::BindOnce(&HasProperDiskAccessPermission, imported_items),
|
||||
base::BindOnce(&BraveImportDataHandler::OnGetDiskAccessPermission,
|
||||
weak_factory_.GetWeakPtr(), source_profile,
|
||||
imported_items));
|
||||
return;
|
||||
}
|
||||
|
||||
ImportDataHandler::StartImport(source_profile, imported_items);
|
||||
}
|
||||
|
||||
void BraveImportDataHandler::OnGetDiskAccessPermission(
|
||||
const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items,
|
||||
bool allowed) {
|
||||
if (!allowed) {
|
||||
// Notify to webui to finish import process and launch tab modal dialog
|
||||
// to guide full disk access information to users.
|
||||
// Guide dialog will be opened after import dialog is closed.
|
||||
FireWebUIListener("import-data-status-changed", base::Value("failed"));
|
||||
|
||||
// Observing web_contents is started here to know the closing timing of
|
||||
// import dialog.
|
||||
Observe(web_ui()->GetWebContents());
|
||||
|
||||
guide_dialog_is_requested_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
return ImportDataHandler::StartImport(source_profile, imported_items);
|
||||
}
|
||||
|
||||
void BraveImportDataHandler::DidStopLoading() {
|
||||
Observe(nullptr);
|
||||
|
||||
if (!guide_dialog_is_requested_)
|
||||
return;
|
||||
|
||||
guide_dialog_is_requested_ = false;
|
||||
|
||||
auto* web_contents = web_ui()->GetWebContents();
|
||||
TabModalConfirmDialog::Create(
|
||||
std::make_unique<FullDiskAccessConfirmDialogDelegate>(
|
||||
web_contents,
|
||||
chrome::FindBrowserWithWebContents(web_contents)),
|
||||
web_contents);
|
||||
}
|
||||
|
||||
} // namespace settings
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "brave/browser/ui/webui/settings/brave_importer_observer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "chrome/browser/importer/external_process_importer_host.h"
|
||||
|
||||
BraveImporterObserver::BraveImporterObserver(
|
||||
ExternalProcessImporterHost* importer_host,
|
||||
const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items,
|
||||
ReportProgressCallback callback)
|
||||
: source_profile_(source_profile),
|
||||
imported_items_(imported_items),
|
||||
callback_(std::move(callback)),
|
||||
importer_host_(importer_host) {
|
||||
DCHECK(importer_host);
|
||||
importer_host->set_observer(this);
|
||||
}
|
||||
|
||||
BraveImporterObserver::~BraveImporterObserver() {
|
||||
if (importer_host_)
|
||||
importer_host_->set_observer(nullptr);
|
||||
}
|
||||
|
||||
// importer::ImporterProgressObserver:
|
||||
void BraveImporterObserver::ImportStarted() {
|
||||
if (import_started_called_)
|
||||
return;
|
||||
import_started_called_ = true;
|
||||
base::Value::Dict data;
|
||||
data.Set("importer_name", source_profile_.importer_name);
|
||||
data.Set("importer_type", source_profile_.importer_type);
|
||||
data.Set("items_to_import", imported_items_);
|
||||
data.Set("event", "ImportStarted");
|
||||
callback_.Run(source_profile_, base::Value(std::move(data)));
|
||||
}
|
||||
|
||||
void BraveImporterObserver::ImportItemStarted(importer::ImportItem item) {
|
||||
base::Value::Dict data;
|
||||
data.Set("importer_name", source_profile_.importer_name);
|
||||
data.Set("importer_type", source_profile_.importer_type);
|
||||
data.Set("items_to_import", imported_items_);
|
||||
data.Set("event", "ImportItemStarted");
|
||||
data.Set("item", item);
|
||||
callback_.Run(source_profile_, base::Value(std::move(data)));
|
||||
}
|
||||
|
||||
void BraveImporterObserver::ImportItemEnded(importer::ImportItem item) {
|
||||
base::Value::Dict data;
|
||||
data.Set("importer_name", source_profile_.importer_name);
|
||||
data.Set("importer_type", source_profile_.importer_type);
|
||||
data.Set("items_to_import", imported_items_);
|
||||
data.Set("event", "ImportItemEnded");
|
||||
data.Set("item", item);
|
||||
callback_.Run(source_profile_, base::Value(std::move(data)));
|
||||
}
|
||||
|
||||
void BraveImporterObserver::ImportEnded() {
|
||||
base::Value::Dict data;
|
||||
data.Set("importer_name", source_profile_.importer_name);
|
||||
data.Set("importer_type", source_profile_.importer_type);
|
||||
data.Set("items_to_import", imported_items_);
|
||||
data.Set("event", "ImportEnded");
|
||||
|
||||
DCHECK(importer_host_);
|
||||
if (importer_host_)
|
||||
importer_host_->set_observer(nullptr);
|
||||
|
||||
importer_host_ = nullptr;
|
||||
|
||||
callback_.Run(source_profile_, base::Value(std::move(data)));
|
||||
}
|
||||
|
||||
ExternalProcessImporterHost*
|
||||
BraveImporterObserver::GetImporterHostForTesting() {
|
||||
return importer_host_.get();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_IMPORTER_OBSERVER_H_
|
||||
#define BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_IMPORTER_OBSERVER_H_
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/importer/importer_progress_observer.h"
|
||||
|
||||
class ExternalProcessImporterHost;
|
||||
|
||||
class BraveImporterObserver : public importer::ImporterProgressObserver {
|
||||
public:
|
||||
using ReportProgressCallback = base::RepeatingCallback<
|
||||
void(const importer::SourceProfile& source_profile, const base::Value&)>;
|
||||
|
||||
BraveImporterObserver(ExternalProcessImporterHost* host,
|
||||
const importer::SourceProfile& source_profile,
|
||||
uint16_t imported_items,
|
||||
ReportProgressCallback callback);
|
||||
~BraveImporterObserver() override;
|
||||
|
||||
void ImportStarted() override;
|
||||
void ImportItemStarted(importer::ImportItem item) override;
|
||||
void ImportItemEnded(importer::ImportItem item) override;
|
||||
void ImportEnded() override;
|
||||
|
||||
private:
|
||||
FRIEND_TEST_ALL_PREFIXES(BraveImporterObserverUnitTest, ImportEvents);
|
||||
|
||||
ExternalProcessImporterHost* GetImporterHostForTesting();
|
||||
|
||||
importer::SourceProfile source_profile_;
|
||||
uint16_t imported_items_ = 0;
|
||||
ReportProgressCallback callback_;
|
||||
// By some reasons ImportStarted event is called few times from different
|
||||
// places, we expect only one call.
|
||||
bool import_started_called_ = false;
|
||||
// If non-null it means importing is in progress. ImporterHost takes care
|
||||
// of deleting itself when import is complete.
|
||||
raw_ptr<ExternalProcessImporterHost> importer_host_; // weak
|
||||
};
|
||||
|
||||
#endif // BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_IMPORTER_OBSERVER_H_
|
||||
@@ -0,0 +1,141 @@
|
||||
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "brave/browser/ui/webui/settings/brave_importer_observer.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "base/json/json_reader.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "brave/browser/importer/brave_external_process_importer_host.h"
|
||||
#include "content/public/test/browser_task_environment.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
class BraveImporterObserverUnitTest : public testing::Test {
|
||||
public:
|
||||
BraveImporterObserverUnitTest() {}
|
||||
|
||||
void SetExpectedInfo(base::Value value) { expected_info_ = std::move(value); }
|
||||
void SetExpectedCalls(int value) { expected_calls_ = value; }
|
||||
int GetExpectedCalls() { return expected_calls_; }
|
||||
void NotifyImportProgress(const importer::SourceProfile& source_profile,
|
||||
const base::Value& info) {
|
||||
EXPECT_EQ(expected_info_, info);
|
||||
expected_calls_++;
|
||||
}
|
||||
|
||||
private:
|
||||
content::BrowserTaskEnvironment task_environment_;
|
||||
base::Value expected_info_;
|
||||
int expected_calls_ = 0;
|
||||
raw_ptr<BraveExternalProcessImporterHost> _ = nullptr;
|
||||
};
|
||||
|
||||
TEST_F(BraveImporterObserverUnitTest, ImportEvents) {
|
||||
auto* importer_host = new BraveExternalProcessImporterHost();
|
||||
importer::SourceProfile source_profile;
|
||||
source_profile.importer_name = u"importer_name";
|
||||
source_profile.importer_type = importer::TYPE_CHROME;
|
||||
source_profile.source_path = base::FilePath(FILE_PATH_LITERAL("test"));
|
||||
auto imported_items = importer::AUTOFILL_FORM_DATA | importer::PASSWORDS;
|
||||
std::unique_ptr<BraveImporterObserver> observer =
|
||||
std::make_unique<BraveImporterObserver>(
|
||||
importer_host, source_profile, imported_items,
|
||||
base::BindRepeating(
|
||||
&BraveImporterObserverUnitTest::NotifyImportProgress,
|
||||
base::Unretained(this)));
|
||||
EXPECT_EQ(importer_host->GetObserverForTesting(), observer.get());
|
||||
EXPECT_EQ(GetExpectedCalls(), 0);
|
||||
|
||||
// Multiple calls for same profile.
|
||||
SetExpectedInfo(*base::JSONReader::Read(R"({
|
||||
"event": "ImportStarted",
|
||||
"importer_name": "importer_name",
|
||||
"importer_type": 1,
|
||||
"items_to_import": 72
|
||||
})"));
|
||||
observer->ImportStarted();
|
||||
observer->ImportStarted();
|
||||
observer->ImportStarted();
|
||||
EXPECT_EQ(GetExpectedCalls(), 1);
|
||||
|
||||
// ImportItemStarted event.
|
||||
SetExpectedCalls(0);
|
||||
EXPECT_EQ(GetExpectedCalls(), 0);
|
||||
SetExpectedInfo(*base::JSONReader::Read(R"({
|
||||
"event": "ImportItemStarted",
|
||||
"importer_name": "importer_name",
|
||||
"importer_type": 1,
|
||||
"item": 8,
|
||||
"items_to_import": 72
|
||||
})"));
|
||||
|
||||
observer->ImportItemStarted(importer::PASSWORDS);
|
||||
EXPECT_EQ(GetExpectedCalls(), 1);
|
||||
|
||||
// ImportItemEnded event.
|
||||
SetExpectedCalls(0);
|
||||
EXPECT_EQ(GetExpectedCalls(), 0);
|
||||
SetExpectedInfo(*base::JSONReader::Read(R"({
|
||||
"event": "ImportItemEnded",
|
||||
"importer_name": "importer_name",
|
||||
"importer_type": 1,
|
||||
"item": 8,
|
||||
"items_to_import": 72
|
||||
})"));
|
||||
|
||||
observer->ImportItemEnded(importer::PASSWORDS);
|
||||
EXPECT_EQ(GetExpectedCalls(), 1);
|
||||
|
||||
// ImportEnded event.
|
||||
SetExpectedCalls(0);
|
||||
EXPECT_EQ(GetExpectedCalls(), 0);
|
||||
SetExpectedInfo(*base::JSONReader::Read(R"({
|
||||
"event": "ImportEnded",
|
||||
"importer_name": "importer_name",
|
||||
"importer_type": 1,
|
||||
"items_to_import": 72
|
||||
})"));
|
||||
|
||||
observer->ImportEnded();
|
||||
EXPECT_EQ(GetExpectedCalls(), 1);
|
||||
EXPECT_EQ(observer->GetImporterHostForTesting(), nullptr);
|
||||
// The observer should be removed on ImportEnded event.
|
||||
EXPECT_EQ(importer_host->GetObserverForTesting(), nullptr);
|
||||
|
||||
// ImportEnded event should not be called anymore.
|
||||
SetExpectedCalls(0);
|
||||
EXPECT_EQ(GetExpectedCalls(), 0);
|
||||
// Destroy host.
|
||||
importer_host->NotifyImportEndedForTesting();
|
||||
EXPECT_EQ(GetExpectedCalls(), 0);
|
||||
}
|
||||
|
||||
TEST_F(BraveImporterObserverUnitTest, DestroyObserverEarly) {
|
||||
auto* importer_host = new BraveExternalProcessImporterHost();
|
||||
importer::SourceProfile source_profile;
|
||||
source_profile.importer_name = u"importer_name";
|
||||
source_profile.importer_type = importer::TYPE_CHROME;
|
||||
source_profile.source_path = base::FilePath(FILE_PATH_LITERAL("test"));
|
||||
auto imported_items = importer::AUTOFILL_FORM_DATA | importer::PASSWORDS;
|
||||
std::unique_ptr<BraveImporterObserver> observer =
|
||||
std::make_unique<BraveImporterObserver>(
|
||||
importer_host, source_profile, imported_items,
|
||||
base::BindRepeating(
|
||||
&BraveImporterObserverUnitTest::NotifyImportProgress,
|
||||
base::Unretained(this)));
|
||||
EXPECT_EQ(importer_host->GetObserverForTesting(), observer.get());
|
||||
EXPECT_EQ(GetExpectedCalls(), 0);
|
||||
observer.reset();
|
||||
EXPECT_EQ(importer_host->GetObserverForTesting(), nullptr);
|
||||
// ImportEnded event should not be called anymore.
|
||||
SetExpectedCalls(0);
|
||||
EXPECT_EQ(GetExpectedCalls(), 0);
|
||||
// Destroy host.
|
||||
importer_host->NotifyImportEndedForTesting();
|
||||
EXPECT_EQ(GetExpectedCalls(), 0);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "brave/browser/ui/webui/settings/import_feature.h"
|
||||
|
||||
#include "base/feature_list.h"
|
||||
#include "base/metrics/field_trial_params.h"
|
||||
|
||||
namespace settings {
|
||||
|
||||
const base::Feature kParallelImports{"ParallelImports",
|
||||
base::FEATURE_ENABLED_BY_DEFAULT};
|
||||
|
||||
// Temporary flag to keep old way until
|
||||
// https://github.com/brave/brave-core/pull/15637 landed.
|
||||
bool IsParallelImportEnabled() {
|
||||
return base::FeatureList::IsEnabled(kParallelImports);
|
||||
}
|
||||
|
||||
} // namespace settings
|
||||
@@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef BRAVE_BROWSER_UI_WEBUI_SETTINGS_IMPORT_FEATURE_H_
|
||||
#define BRAVE_BROWSER_UI_WEBUI_SETTINGS_IMPORT_FEATURE_H_
|
||||
|
||||
#include "base/feature_list.h"
|
||||
|
||||
namespace settings {
|
||||
bool IsParallelImportEnabled();
|
||||
} // namespace settings
|
||||
|
||||
#endif // BRAVE_BROWSER_UI_WEBUI_SETTINGS_IMPORT_FEATURE_H_
|
||||
@@ -381,6 +381,7 @@ test("brave_unit_tests") {
|
||||
"//brave/app:brave_generated_resources_grit",
|
||||
"//brave/browser/ui/color:unit_tests",
|
||||
"//brave/browser/ui/toolbar:brave_app_menu_unit_test",
|
||||
"//brave/browser/ui/webui/settings:unittests",
|
||||
"//brave/components/brave_shields/common:mojom",
|
||||
"//brave/components/brave_wallet/browser:pref_names",
|
||||
"//brave/components/brave_wallet/browser:utils",
|
||||
|
||||
Reference in New Issue
Block a user