From 4650b9c817c63593b688ce9bfdbdaafdef2c2ae2 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 14 Dec 2020 12:00:40 -0500 Subject: [PATCH 1/9] Uplift of Sync from 1.20.x --- app/brave_generated_resources.grd | 8 +- app/brave_strings.grd | 8 +- app/generated_resources.grd | 8 +- browser/BUILD.gn | 3 +- browser/sync/BUILD.gn | 12 + .../brave_profile_sync_service_delegate.cc | 30 +- .../brave_profile_sync_service_delegate.h | 5 +- build/commands/lib/config.js | 2 +- chromium_src/base/mac/foundation_util.mm | 7 +- .../sync/profile_sync_service_factory.cc | 3 +- .../core/browser/cookie_settings_util.cc | 26 + .../core/browser/host_content_settings_map.cc | 9 +- .../sync_device_info/device_info.cc | 26 + .../components/sync_device_info/device_info.h | 18 + .../browser/application_context_impl.mm | 352 ++++++++++ .../browser_state_keyed_service_factories.mm | 50 ++ .../ios/chrome/browser/prefs/BUILD.gn | 10 + .../ios/chrome/browser/prefs/browser_prefs.mm | 13 + .../signin/about_signin_internals_factory.cc | 44 ++ .../sync/profile_sync_service_factory.cc | 18 + components/brave_sync/BUILD.gn | 2 + .../driver/brave_sync_profile_sync_service.cc | 1 + .../driver/profile_sync_service_delegate.h | 9 +- ios/CPPLINT.cfg | 2 + ios/app/BUILD.gn | 47 ++ ios/app/brave_core_main.h | 28 + ios/app/brave_core_main.mm | 109 +++ ios/app/brave_main_delegate.h | 32 + ios/app/brave_main_delegate.mm | 61 ++ ios/app/headers.gni | 13 + ios/browser/BUILD.gn | 42 ++ ios/browser/api/bookmarks/BUILD.gn | 38 + .../api/bookmarks/brave_bookmarks_api.h | 141 ++++ .../api/bookmarks/brave_bookmarks_api.mm | 653 ++++++++++++++++++ .../api/bookmarks/brave_bookmarks_observer.h | 43 ++ .../api/bookmarks/brave_bookmarks_observer.mm | 211 ++++++ ios/browser/api/bookmarks/exporter/BUILD.gn | 41 ++ .../exporter/bookmark_html_writer.cc | 609 ++++++++++++++++ .../bookmarks/exporter/bookmark_html_writer.h | 50 ++ .../bookmarks/exporter/bookmarks_encoder.cc | 29 + .../bookmarks/exporter/bookmarks_encoder.h | 29 + .../exporter/brave_bookmarks_exporter.h | 38 + .../exporter/brave_bookmarks_exporter.mm | 207 ++++++ ios/browser/api/bookmarks/importer/BUILD.gn | 46 ++ .../importer/bookmark_html_reader.cc | 507 ++++++++++++++ .../bookmarks/importer/bookmark_html_reader.h | 107 +++ .../bookmarks/importer/bookmarks_importer.cc | 182 +++++ .../bookmarks/importer/bookmarks_importer.h | 23 + .../importer/brave_bookmarks_importer.h | 50 ++ .../importer/brave_bookmarks_importer.mm | 252 +++++++ .../api/bookmarks/importer/favicon_reencode.h | 25 + .../bookmarks/importer/favicon_reencode.mm | 66 ++ .../importer/imported_bookmark_entry.cc | 25 + .../importer/imported_bookmark_entry.h | 30 + ios/browser/api/sync/BUILD.gn | 36 + ios/browser/api/sync/brave_sync_api.h | 43 ++ ios/browser/api/sync/brave_sync_api.mm | 221 ++++++ ios/browser/api/sync/brave_sync_worker.cc | 371 ++++++++++ ios/browser/api/sync/brave_sync_worker.h | 92 +++ ios/browser/brave_web_client.h | 40 ++ ios/browser/brave_web_client.mm | 48 ++ ios/browser/brave_web_main_parts.h | 49 ++ ios/browser/brave_web_main_parts.mm | 132 ++++ ios/browser/metrics/BUILD.gn | 24 + ...os_brave_metrics_services_manager_client.h | 40 ++ ...s_brave_metrics_services_manager_client.mm | 43 ++ ...hrome-browser-prefs-browser_prefs.mm.patch | 12 + ...sync-profile_sync_service_factory.cc.patch | 13 + vendor/brave-ios/.DS_Store | Bin 0 -> 8196 bytes vendor/brave-ios/Ads/BATAdNotification.h | 2 + vendor/brave-ios/Ads/BATBraveAds.h | 2 + vendor/brave-ios/Ads/BATBraveAds.mm | 65 +- vendor/brave-ios/BATBraveRewards.h | 4 + vendor/brave-ios/BUILD.gn | 10 +- vendor/brave-ios/BraveRewards.h | 12 + vendor/brave-ios/Ledger/BATBraveLedger.h | 9 +- vendor/brave-ios/Ledger/BATBraveLedger.mm | 150 ++-- .../brave-ios/Ledger/BATBraveLedgerObserver.h | 1 + .../brave-ios/Ledger/Data/BATLedgerDatabase.h | 1 + vendor/brave-ios/Ledger/Data/DataController.h | 1 + .../Ledger/Data/Model/ActivityInfo.h | 1 + .../Ledger/Data/Model/ContributionInfo.h | 1 + .../Ledger/Data/Model/ContributionPublisher.h | 1 + .../Ledger/Data/Model/ContributionQueue.h | 1 + .../Ledger/Data/Model/MediaPublisherInfo.h | 1 + .../Ledger/Data/Model/PendingContribution.h | 1 + .../brave-ios/Ledger/Data/Model/Promotion.h | 1 + .../Ledger/Data/Model/PromotionCredentials.h | 1 + .../Ledger/Data/Model/PublisherInfo.h | 1 + .../Ledger/Data/Model/RecurringDonation.h | 1 + .../Ledger/Data/Model/ServerPublisherAmount.h | 1 + .../Ledger/Data/Model/ServerPublisherBanner.h | 1 + .../Ledger/Data/Model/ServerPublisherInfo.h | 1 + .../Ledger/Data/Model/ServerPublisherLink.h | 1 + .../Ledger/Data/Model/UnblindedToken.h | 1 + .../Ledger/Models/BATPromotionSolution.h | 1 + .../Ledger/Models/BATRewardsNotification.h | 1 + vendor/brave-ios/Shared/BATCommonOperations.h | 1 + vendor/brave-ios/Shared/NSURL+Extensions.h | 1 + .../objc-gen/objc-gen/Interface.swift | 1 + .../objc_templates/interface_declaration.tmpl | 1 + vendor/brave-ios/tests/BUILD.gn | 4 +- vendor/brave-ios/tests/ads_wrapper_test.mm | 5 + 103 files changed, 5725 insertions(+), 126 deletions(-) create mode 100644 browser/sync/BUILD.gn create mode 100644 chromium_src/components/content_settings/core/browser/cookie_settings_util.cc create mode 100644 chromium_src/components/sync_device_info/device_info.cc create mode 100644 chromium_src/components/sync_device_info/device_info.h create mode 100644 chromium_src/ios/chrome/browser/application_context_impl.mm create mode 100644 chromium_src/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm create mode 100644 chromium_src/ios/chrome/browser/prefs/BUILD.gn create mode 100644 chromium_src/ios/chrome/browser/prefs/browser_prefs.mm create mode 100644 chromium_src/ios/chrome/browser/signin/about_signin_internals_factory.cc create mode 100644 chromium_src/ios/chrome/browser/sync/profile_sync_service_factory.cc create mode 100644 ios/CPPLINT.cfg create mode 100644 ios/app/BUILD.gn create mode 100644 ios/app/brave_core_main.h create mode 100644 ios/app/brave_core_main.mm create mode 100644 ios/app/brave_main_delegate.h create mode 100644 ios/app/brave_main_delegate.mm create mode 100644 ios/app/headers.gni create mode 100644 ios/browser/BUILD.gn create mode 100644 ios/browser/api/bookmarks/BUILD.gn create mode 100644 ios/browser/api/bookmarks/brave_bookmarks_api.h create mode 100644 ios/browser/api/bookmarks/brave_bookmarks_api.mm create mode 100644 ios/browser/api/bookmarks/brave_bookmarks_observer.h create mode 100644 ios/browser/api/bookmarks/brave_bookmarks_observer.mm create mode 100644 ios/browser/api/bookmarks/exporter/BUILD.gn create mode 100644 ios/browser/api/bookmarks/exporter/bookmark_html_writer.cc create mode 100644 ios/browser/api/bookmarks/exporter/bookmark_html_writer.h create mode 100644 ios/browser/api/bookmarks/exporter/bookmarks_encoder.cc create mode 100644 ios/browser/api/bookmarks/exporter/bookmarks_encoder.h create mode 100644 ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.h create mode 100644 ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.mm create mode 100644 ios/browser/api/bookmarks/importer/BUILD.gn create mode 100644 ios/browser/api/bookmarks/importer/bookmark_html_reader.cc create mode 100644 ios/browser/api/bookmarks/importer/bookmark_html_reader.h create mode 100644 ios/browser/api/bookmarks/importer/bookmarks_importer.cc create mode 100644 ios/browser/api/bookmarks/importer/bookmarks_importer.h create mode 100644 ios/browser/api/bookmarks/importer/brave_bookmarks_importer.h create mode 100644 ios/browser/api/bookmarks/importer/brave_bookmarks_importer.mm create mode 100644 ios/browser/api/bookmarks/importer/favicon_reencode.h create mode 100644 ios/browser/api/bookmarks/importer/favicon_reencode.mm create mode 100644 ios/browser/api/bookmarks/importer/imported_bookmark_entry.cc create mode 100644 ios/browser/api/bookmarks/importer/imported_bookmark_entry.h create mode 100644 ios/browser/api/sync/BUILD.gn create mode 100644 ios/browser/api/sync/brave_sync_api.h create mode 100644 ios/browser/api/sync/brave_sync_api.mm create mode 100644 ios/browser/api/sync/brave_sync_worker.cc create mode 100644 ios/browser/api/sync/brave_sync_worker.h create mode 100644 ios/browser/brave_web_client.h create mode 100644 ios/browser/brave_web_client.mm create mode 100644 ios/browser/brave_web_main_parts.h create mode 100644 ios/browser/brave_web_main_parts.mm create mode 100644 ios/browser/metrics/BUILD.gn create mode 100644 ios/browser/metrics/ios_brave_metrics_services_manager_client.h create mode 100644 ios/browser/metrics/ios_brave_metrics_services_manager_client.mm create mode 100644 patches/ios-chrome-browser-prefs-browser_prefs.mm.patch create mode 100644 patches/ios-chrome-browser-sync-profile_sync_service_factory.cc.patch create mode 100644 vendor/brave-ios/.DS_Store diff --git a/app/brave_generated_resources.grd b/app/brave_generated_resources.grd index 2a70f455787a..cde987241733 100644 --- a/app/brave_generated_resources.grd +++ b/app/brave_generated_resources.grd @@ -48,7 +48,13 @@ - + + + + + + + diff --git a/app/brave_strings.grd b/app/brave_strings.grd index 13f69493b69d..66acc72f1999 100644 --- a/app/brave_strings.grd +++ b/app/brave_strings.grd @@ -49,7 +49,13 @@ If you update this file, be sure also to update google_chrome_strings.grd. --> - + + + + + + + diff --git a/app/generated_resources.grd b/app/generated_resources.grd index c888c51ebd92..16ac532dc1b2 100644 --- a/app/generated_resources.grd +++ b/app/generated_resources.grd @@ -53,7 +53,13 @@ are declared in tools/grit/grit_rule.gni. - + + + + + + + diff --git a/browser/BUILD.gn b/browser/BUILD.gn index 5aa701bca581..c71e3ec43cae 100644 --- a/browser/BUILD.gn +++ b/browser/BUILD.gn @@ -85,8 +85,6 @@ source_set("browser_process") { "search_engines/search_engine_tracker.h", "search_engines/tor_window_search_engine_provider_service.cc", "search_engines/tor_window_search_engine_provider_service.h", - "sync/brave_profile_sync_service_delegate.cc", - "sync/brave_profile_sync_service_delegate.h", "update_util.cc", "update_util.h", ] @@ -121,6 +119,7 @@ source_set("browser_process") { "profiles", "renderer_context_menu", "search", + "sync", "themes", "ui", "//base", diff --git a/browser/sync/BUILD.gn b/browser/sync/BUILD.gn new file mode 100644 index 000000000000..90a30e51c146 --- /dev/null +++ b/browser/sync/BUILD.gn @@ -0,0 +1,12 @@ +source_set("sync") { + sources = [ + "brave_profile_sync_service_delegate.cc", + "brave_profile_sync_service_delegate.h", + ] + + deps = [ + "//base", + "//components/sync/driver", + "//components/sync_device_info", + ] +} diff --git a/browser/sync/brave_profile_sync_service_delegate.cc b/browser/sync/brave_profile_sync_service_delegate.cc index ea859c9e8222..666f90cfcd79 100644 --- a/browser/sync/brave_profile_sync_service_delegate.cc +++ b/browser/sync/brave_profile_sync_service_delegate.cc @@ -8,31 +8,19 @@ #include #include "base/task/post_task.h" +#include "base/threading/thread_task_runner_handle.h" #include "brave/components/sync/driver/brave_sync_profile_sync_service.h" #include "chrome/browser/sync/device_info_sync_service_factory.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "components/sync_device_info/device_info_sync_service.h" #include "components/sync_device_info/device_info_tracker.h" #include "components/sync_device_info/local_device_info_provider.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" namespace syncer { -namespace { -syncer::BraveProfileSyncService* GetSyncService(Profile* profile) { - return ProfileSyncServiceFactory::IsSyncAllowed(profile) - ? static_cast( - ProfileSyncServiceFactory::GetForProfile(profile)) - : nullptr; -} -} // namespace - BraveProfileSyncServiceDelegate::BraveProfileSyncServiceDelegate( - Profile* profile) - : device_info_sync_service_( - DeviceInfoSyncServiceFactory::GetForProfile(profile)), - profile_(profile), + DeviceInfoSyncService* device_info_sync_service) + : device_info_sync_service_(device_info_sync_service), weak_ptr_factory_(this) { DCHECK(device_info_sync_service_); @@ -48,7 +36,8 @@ BraveProfileSyncServiceDelegate::BraveProfileSyncServiceDelegate( BraveProfileSyncServiceDelegate::~BraveProfileSyncServiceDelegate() {} void BraveProfileSyncServiceDelegate::OnDeviceInfoChange() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(profile_sync_service_); + const syncer::DeviceInfo* local_device_info = local_device_info_provider_->GetLocalDeviceInfo(); @@ -66,17 +55,16 @@ void BraveProfileSyncServiceDelegate::OnDeviceInfoChange() { if (!found_local_device) { // We can't call OnSelfDeviceInfoDeleted directly because we are on // remove device execution path, so posting task - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce( &BraveProfileSyncServiceDelegate::OnSelfDeviceInfoDeleted, weak_ptr_factory_.GetWeakPtr())); } } -void BraveProfileSyncServiceDelegate::OnSelfDeviceInfoDeleted(void) { - syncer::BraveProfileSyncService* sync_service = GetSyncService(profile_); - sync_service->OnSelfDeviceInfoDeleted(base::DoNothing::Once()); +void BraveProfileSyncServiceDelegate::OnSelfDeviceInfoDeleted() { + profile_sync_service_->OnSelfDeviceInfoDeleted(base::DoNothing::Once()); } void BraveProfileSyncServiceDelegate::SuspendDeviceObserverForOwnReset() { diff --git a/browser/sync/brave_profile_sync_service_delegate.h b/browser/sync/brave_profile_sync_service_delegate.h index 94c432cd68f9..8bdbc5c3e94f 100644 --- a/browser/sync/brave_profile_sync_service_delegate.h +++ b/browser/sync/brave_profile_sync_service_delegate.h @@ -17,6 +17,7 @@ class Profile; namespace syncer { +class DeviceInfoSyncService; class DeviceInfoTracker; class LocalDeviceInfoProvider; @@ -26,7 +27,8 @@ class BraveProfileSyncServiceDelegate : public ProfileSyncServiceDelegate, public syncer::DeviceInfoTracker::Observer { public: - explicit BraveProfileSyncServiceDelegate(Profile* profile); + explicit BraveProfileSyncServiceDelegate( + DeviceInfoSyncService* device_info_sync_service); ~BraveProfileSyncServiceDelegate() override; void SuspendDeviceObserverForOwnReset() override; @@ -44,7 +46,6 @@ class BraveProfileSyncServiceDelegate device_info_observer_{this}; DeviceInfoSyncService* device_info_sync_service_; - Profile* profile_; base::WeakPtrFactory weak_ptr_factory_; diff --git a/build/commands/lib/config.js b/build/commands/lib/config.js index 2cc44fd74f78..d656f36c7522 100755 --- a/build/commands/lib/config.js +++ b/build/commands/lib/config.js @@ -42,7 +42,7 @@ var packageConfig = function(key){ const getNPMConfig = (key) => { if (!NpmConfig) { - const list = run(npmCommand, ['config', 'list', '--json'], {cwd: rootDir}) + const list = run(npmCommand, ['config', 'list', '--json', '--userconfig=' + path.join(rootDir, '.npmrc')]) NpmConfig = JSON.parse(list.stdout.toString()) } diff --git a/chromium_src/base/mac/foundation_util.mm b/chromium_src/base/mac/foundation_util.mm index e8accb521cc1..67d9c9c10096 100644 --- a/chromium_src/base/mac/foundation_util.mm +++ b/chromium_src/base/mac/foundation_util.mm @@ -25,7 +25,12 @@ // build and chrome::GetChannel() will always return stable in test build. // // For safe in non-test build, current seems fine in official build. +#if defined(OS_IOS) +#include "ios/chrome/common/channel_info.h" +#else #include "chrome/common/channel_info.h" +using chrome::GetChannel; +#endif #endif namespace base { @@ -39,7 +44,7 @@ #if !defined(OFFICIAL_BUILD) return "com.brave.Browser.development"; #else - switch (chrome::GetChannel()) { + switch (GetChannel()) { case version_info::Channel::CANARY: return "com.brave.Browser.nightly"; case version_info::Channel::DEV: diff --git a/chromium_src/chrome/browser/sync/profile_sync_service_factory.cc b/chromium_src/chrome/browser/sync/profile_sync_service_factory.cc index 475e3618d317..f49294eb4954 100644 --- a/chromium_src/chrome/browser/sync/profile_sync_service_factory.cc +++ b/chromium_src/chrome/browser/sync/profile_sync_service_factory.cc @@ -10,7 +10,8 @@ #define BRAVE_BUILD_SERVICE_INSTANCE_FOR \ std::make_unique( \ std::move(init_params), \ - std::make_unique(profile)); + std::make_unique( \ + DeviceInfoSyncServiceFactory::GetForProfile(profile))); #include "../../../../../chrome/browser/sync/profile_sync_service_factory.cc" diff --git a/chromium_src/components/content_settings/core/browser/cookie_settings_util.cc b/chromium_src/components/content_settings/core/browser/cookie_settings_util.cc new file mode 100644 index 000000000000..8c3e64af75eb --- /dev/null +++ b/chromium_src/components/content_settings/core/browser/cookie_settings_util.cc @@ -0,0 +1,26 @@ +/* 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 "base/build_config.h" + +#if defined(OS_IOS) +#define SettingsAllowSigninCookies SettingsAllowSigninCookies_ChromiumImpl +#define SettingsDeleteSigninCookiesOnExit \ + SettingsDeleteSigninCookiesOnExit_ChromiumImpl +#endif + +#include "../../../../../../components/content_settings/core/browser/cookie_settings_utils.cc" + +#if defined(OS_IOS) +bool SettingsAllowSigninCookies( + const content_settings::CookieSettings* cookie_settings) { + return false; +} + +bool SettingsDeleteSigninCookiesOnExit( + const content_settings::CookieSettings* cookie_settings) { + return true; +} +#endif diff --git a/chromium_src/components/content_settings/core/browser/host_content_settings_map.cc b/chromium_src/components/content_settings/core/browser/host_content_settings_map.cc index 3c72f8e89e8b..aedee4e2be13 100644 --- a/chromium_src/components/content_settings/core/browser/host_content_settings_map.cc +++ b/chromium_src/components/content_settings/core/browser/host_content_settings_map.cc @@ -1,7 +1,13 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* 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 "build/build_config.h" + +#if defined(OS_IOS) +#include "../../../../../../components/content_settings/core/browser/host_content_settings_map.cc" +#else #include "brave/components/content_settings/core/browser/brave_content_settings_ephemeral_provider.h" #include "brave/components/content_settings/core/browser/brave_content_settings_pref_provider.h" @@ -10,3 +16,4 @@ #include "../../../../../../components/content_settings/core/browser/host_content_settings_map.cc" #undef EphemeralProvider #undef PrefProvider +#endif diff --git a/chromium_src/components/sync_device_info/device_info.cc b/chromium_src/components/sync_device_info/device_info.cc new file mode 100644 index 000000000000..b2511e41d284 --- /dev/null +++ b/chromium_src/components/sync_device_info/device_info.cc @@ -0,0 +1,26 @@ +/* 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 "components/sync_device_info/device_info.h" + +#include + +#define ToValue ToValue_ChromiumImpl +#include "../../../../components/sync_device_info/device_info.cc" +#undef ToValue + +namespace syncer { +std::unique_ptr DeviceInfo::ToValue() const { + std::unique_ptr value = ToValue_ChromiumImpl(); + if ((device_type_ == sync_pb::SyncEnums_DeviceType_TYPE_PHONE || + device_type_ == sync_pb::SyncEnums_DeviceType_TYPE_TABLET) && + sync_user_agent_.find("IOS") != std::string::npos) { + value->SetString("os", "ios"); + } else { + value->SetString("os", GetOSString()); + } + return value; +} +} // namespace syncer diff --git a/chromium_src/components/sync_device_info/device_info.h b/chromium_src/components/sync_device_info/device_info.h new file mode 100644 index 000000000000..dcea822cbebd --- /dev/null +++ b/chromium_src/components/sync_device_info/device_info.h @@ -0,0 +1,18 @@ +/* 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_CHROMIUM_SRC_COMPONENTS_SYNC_DEVICE_INFO_DEVICE_INFO_H_ +#define BRAVE_CHROMIUM_SRC_COMPONENTS_SYNC_DEVICE_INFO_DEVICE_INFO_H_ + +#include + +#define ToValue \ + ToValue_ChromiumImpl() const; \ + std::unique_ptr ToValue + +#include "../../../../components/sync_device_info/device_info.h" +#undef ToValue + +#endif // BRAVE_CHROMIUM_SRC_COMPONENTS_SYNC_DEVICE_INFO_DEVICE_INFO_H_ diff --git a/chromium_src/ios/chrome/browser/application_context_impl.mm b/chromium_src/ios/chrome/browser/application_context_impl.mm new file mode 100644 index 000000000000..92fc35948f7a --- /dev/null +++ b/chromium_src/ios/chrome/browser/application_context_impl.mm @@ -0,0 +1,352 @@ +/* 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 "ios/chrome/browser/application_context_impl.h" + +#include + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/path_service.h" +#include "base/sequenced_task_runner.h" +#include "base/task/post_task.h" +#include "base/time/default_clock.h" +#include "base/time/default_tick_clock.h" +#include "brave/ios/browser/metrics/ios_brave_metrics_services_manager_client.h" +#include "components/component_updater/component_updater_service.h" +#include "components/gcm_driver/gcm_driver.h" +#include "components/history/core/browser/history_service.h" +#include "components/keyed_service/core/service_access_type.h" +#include "components/metrics/metrics_service.h" +#include "components/metrics_services_manager/metrics_services_manager.h" +#include "components/net_log/net_export_file_writer.h" +#include "components/network_time/network_time_tracker.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" +#include "components/sessions/core/session_id_generator.h" +#include "components/ukm/ukm_service.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.h" +#include "ios/chrome/browser/chrome_paths.h" +#import "ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h" +#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.h" +#include "ios/chrome/browser/history/history_service_factory.h" +#include "ios/chrome/browser/ios_chrome_io_thread.h" +#include "ios/chrome/browser/policy/browser_policy_connector_ios.h" +#include "ios/chrome/browser/pref_names.h" +#include "ios/chrome/browser/prefs/browser_prefs.h" +#include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h" +#import "ios/chrome/browser/safe_browsing/safe_browsing_service.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "net/log/net_log.h" +#include "net/log/net_log_capture_mode.h" +#include "net/socket/client_socket_pool_manager.h" +#include "net/url_request/url_request_context_getter.h" +#include "services/metrics/public/cpp/ukm_recorder.h" +#include "services/network/network_change_manager.h" +#include "services/network/public/cpp/network_connection_tracker.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +// Passed to NetworkConnectionTracker to bind a NetworkChangeManager receiver. +void BindNetworkChangeManagerReceiver( + network::NetworkChangeManager* network_change_manager, + mojo::PendingReceiver receiver) { + network_change_manager->AddReceiver(std::move(receiver)); +} + +} // namespace + +ApplicationContextImpl::ApplicationContextImpl( + base::SequencedTaskRunner* local_state_task_runner, + const base::CommandLine& command_line, + const std::string& locale) + : local_state_task_runner_(local_state_task_runner), + was_last_shutdown_clean_(false) { + DCHECK(!GetApplicationContext()); + SetApplicationContext(this); + + SetApplicationLocale(locale); + + // update_client::UpdateQueryParams::SetDelegate( + // IOSChromeUpdateQueryParamsDelegate::GetInstance()); +} + +ApplicationContextImpl::~ApplicationContextImpl() { + DCHECK_EQ(this, GetApplicationContext()); + SetApplicationContext(nullptr); +} + +void ApplicationContextImpl::PreCreateThreads() { + DCHECK(thread_checker_.CalledOnValidThread()); + ios_chrome_io_thread_.reset( + new IOSChromeIOThread(GetLocalState(), GetNetLog())); +} + +void ApplicationContextImpl::PreMainMessageLoopRun() { + DCHECK(thread_checker_.CalledOnValidThread()); +} + +void ApplicationContextImpl::StartTearDown() { + DCHECK(thread_checker_.CalledOnValidThread()); + // We need to destroy the NetworkTimeTracker before the IO thread gets + // destroyed, since the destructor can call the URLFetcher destructor, + // which does a PostDelayedTask operation on the IO thread. (The IO thread + // will handle that URLFetcher operation before going away.) + network_time_tracker_.reset(); + + net_export_file_writer_.reset(); + + // Need to clear browser states before the IO thread. + chrome_browser_state_manager_.reset(); + + if (local_state_) { + local_state_->CommitPendingWrite(); + sessions::SessionIdGenerator::GetInstance()->Shutdown(); + } + + ios_chrome_io_thread_->NetworkTearDown(); +} + +void ApplicationContextImpl::PostDestroyThreads() { + DCHECK(thread_checker_.CalledOnValidThread()); + // Resets associated state right after actual thread is stopped as + // IOSChromeIOThread::Globals cleanup happens in CleanUp on the IO + // thread, i.e. as the thread exits its message loop. + // + // This is important because in various places, the IOSChromeIOThread + // object being NULL is considered synonymous with the IO thread + // having stopped. + ios_chrome_io_thread_.reset(); +} + +void ApplicationContextImpl::OnAppEnterForeground() { + DCHECK(thread_checker_.CalledOnValidThread()); + + PrefService* local_state = GetLocalState(); + local_state->SetBoolean(prefs::kLastSessionExitedCleanly, false); +} + +void ApplicationContextImpl::OnAppEnterBackground() { + DCHECK(thread_checker_.CalledOnValidThread()); + // Mark all the ChromeBrowserStates as clean and persist history. + std::vector loaded_browser_state = + GetChromeBrowserStateManager()->GetLoadedBrowserStates(); + for (ChromeBrowserState* browser_state : loaded_browser_state) { + if (history::HistoryService* history_service = + ios::HistoryServiceFactory::GetForBrowserStateIfExists( + browser_state, ServiceAccessType::EXPLICIT_ACCESS)) { + history_service->HandleBackgrounding(); + } + + PrefService* browser_state_prefs = browser_state->GetPrefs(); + if (browser_state_prefs) + browser_state_prefs->CommitPendingWrite(); + } + + PrefService* local_state = GetLocalState(); + local_state->SetBoolean(prefs::kLastSessionExitedCleanly, true); +} + +bool ApplicationContextImpl::WasLastShutdownClean() { + DCHECK(thread_checker_.CalledOnValidThread()); + // Make sure the locale state is created as the file is initialized there. + ignore_result(GetLocalState()); + return was_last_shutdown_clean_; +} + +PrefService* ApplicationContextImpl::GetLocalState() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!local_state_) + CreateLocalState(); + return local_state_.get(); +} + +net::URLRequestContextGetter* +ApplicationContextImpl::GetSystemURLRequestContext() { + DCHECK(thread_checker_.CalledOnValidThread()); + return ios_chrome_io_thread_->system_url_request_context_getter(); +} + +scoped_refptr +ApplicationContextImpl::GetSharedURLLoaderFactory() { + return ios_chrome_io_thread_->GetSharedURLLoaderFactory(); +} + +network::mojom::NetworkContext* +ApplicationContextImpl::GetSystemNetworkContext() { + return ios_chrome_io_thread_->GetSystemNetworkContext(); +} + +const std::string& ApplicationContextImpl::GetApplicationLocale() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!application_locale_.empty()); + return application_locale_; +} + +ios::ChromeBrowserStateManager* +ApplicationContextImpl::GetChromeBrowserStateManager() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!chrome_browser_state_manager_) + chrome_browser_state_manager_.reset(new ChromeBrowserStateManagerImpl()); + return chrome_browser_state_manager_.get(); +} + +metrics_services_manager::MetricsServicesManager* +ApplicationContextImpl::GetMetricsServicesManager() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!metrics_services_manager_) { + metrics_services_manager_.reset( + new metrics_services_manager::MetricsServicesManager( + std::make_unique( + GetLocalState()))); + } + return metrics_services_manager_.get(); +} + +metrics::MetricsService* ApplicationContextImpl::GetMetricsService() { + DCHECK(thread_checker_.CalledOnValidThread()); + return GetMetricsServicesManager()->GetMetricsService(); +} + +ukm::UkmRecorder* ApplicationContextImpl::GetUkmRecorder() { + DCHECK(thread_checker_.CalledOnValidThread()); + return GetMetricsServicesManager()->GetUkmService(); +} + +variations::VariationsService* ApplicationContextImpl::GetVariationsService() { + DCHECK(thread_checker_.CalledOnValidThread()); + return GetMetricsServicesManager()->GetVariationsService(); +} + +rappor::RapporServiceImpl* ApplicationContextImpl::GetRapporServiceImpl() { + DCHECK(thread_checker_.CalledOnValidThread()); + return GetMetricsServicesManager()->GetRapporServiceImpl(); +} + +net::NetLog* ApplicationContextImpl::GetNetLog() { + DCHECK(thread_checker_.CalledOnValidThread()); + return net::NetLog::Get(); +} + +net_log::NetExportFileWriter* ApplicationContextImpl::GetNetExportFileWriter() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!net_export_file_writer_) { + net_export_file_writer_ = std::make_unique(); + } + return net_export_file_writer_.get(); +} + +network_time::NetworkTimeTracker* +ApplicationContextImpl::GetNetworkTimeTracker() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!network_time_tracker_) { + network_time_tracker_.reset(new network_time::NetworkTimeTracker( + base::WrapUnique(new base::DefaultClock), + base::WrapUnique(new base::DefaultTickClock), GetLocalState(), + GetSharedURLLoaderFactory())); + } + return network_time_tracker_.get(); +} + +IOSChromeIOThread* ApplicationContextImpl::GetIOSChromeIOThread() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(ios_chrome_io_thread_.get()); + return ios_chrome_io_thread_.get(); +} + +gcm::GCMDriver* ApplicationContextImpl::GetGCMDriver() { + DCHECK(thread_checker_.CalledOnValidThread()); + return nullptr; +} + +component_updater::ComponentUpdateService* +ApplicationContextImpl::GetComponentUpdateService() { + DCHECK(thread_checker_.CalledOnValidThread()); + // if (!component_updater_) { + // // Creating the component updater does not do anything, components need to + // // be registered and Start() needs to be called. + // component_updater_ = component_updater::ComponentUpdateServiceFactory( + // component_updater::MakeIOSComponentUpdaterConfigurator( + // base::CommandLine::ForCurrentProcess()), + // std::make_unique()); + // } + // return component_updater_.get(); + return nullptr; +} + +SafeBrowsingService* ApplicationContextImpl::GetSafeBrowsingService() { + DCHECK(thread_checker_.CalledOnValidThread()); + return nullptr; +} + +network::NetworkConnectionTracker* +ApplicationContextImpl::GetNetworkConnectionTracker() { + if (!network_connection_tracker_) { + if (!network_change_manager_) { + network_change_manager_ = + std::make_unique(nullptr); + } + network_connection_tracker_ = + std::make_unique(base::BindRepeating( + &BindNetworkChangeManagerReceiver, + base::Unretained(network_change_manager_.get()))); + } + return network_connection_tracker_.get(); +} + +BrowserPolicyConnectorIOS* ApplicationContextImpl::GetBrowserPolicyConnector() { + DCHECK(thread_checker_.CalledOnValidThread()); + return nullptr; +} + +void ApplicationContextImpl::SetApplicationLocale(const std::string& locale) { + DCHECK(thread_checker_.CalledOnValidThread()); + application_locale_ = locale; +} + +void ApplicationContextImpl::CreateLocalState() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!local_state_); + + base::FilePath local_state_path; + CHECK(base::PathService::Get(ios::FILE_LOCAL_STATE, &local_state_path)); + scoped_refptr pref_registry(new PrefRegistrySimple); + + // Register local state preferences. + RegisterLocalStatePrefs(pref_registry.get()); + + local_state_ = ::CreateLocalState( + local_state_path, local_state_task_runner_.get(), pref_registry, + nullptr, nullptr); + DCHECK(local_state_); + + sessions::SessionIdGenerator::GetInstance()->Init(local_state_.get()); + + net::ClientSocketPoolManager::set_max_sockets_per_proxy_server( + net::HttpNetworkSession::NORMAL_SOCKET_POOL, + std::max(std::min(net::kDefaultMaxSocketsPerProxyServer, 99), + net::ClientSocketPoolManager::max_sockets_per_group( + net::HttpNetworkSession::NORMAL_SOCKET_POOL))); + + // Register the shutdown state before anything changes it. + if (local_state_->HasPrefPath(prefs::kLastSessionExitedCleanly)) { + was_last_shutdown_clean_ = + local_state_->GetBoolean(prefs::kLastSessionExitedCleanly); + } +} + +void ApplicationContextImpl::CreateGCMDriver() { + DCHECK(thread_checker_.CalledOnValidThread()); +} diff --git a/chromium_src/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm b/chromium_src/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm new file mode 100644 index 000000000000..1039a3e7f994 --- /dev/null +++ b/chromium_src/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm @@ -0,0 +1,50 @@ +/* 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 "ios/chrome/browser/browser_state/browser_state_keyed_service_factories.h" + +#include "ios/chrome/browser/autofill/personal_data_manager_factory.h" +#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" +#include "ios/chrome/browser/favicon/favicon_service_factory.h" +#include "ios/chrome/browser/history/history_service_factory.h" +#include "ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.h" +#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h" +#include "ios/chrome/browser/reading_list/reading_list_model_factory.h" +#include "ios/chrome/browser/search_engines/template_url_service_factory.h" +#include "ios/chrome/browser/signin/account_consistency_service_factory.h" +#include "ios/chrome/browser/signin/identity_manager_factory.h" +#include "ios/chrome/browser/sync/consent_auditor_factory.h" +#include "ios/chrome/browser/sync/ios_user_event_service_factory.h" +#include "ios/chrome/browser/sync/model_type_store_service_factory.h" +#include "ios/chrome/browser/sync/profile_sync_service_factory.h" +#include "ios/chrome/browser/sync/session_sync_service_factory.h" +#include "ios/chrome/browser/sync/sync_setup_service_factory.h" +#include "ios/chrome/browser/undo/bookmark_undo_service_factory.h" +#include "ios/chrome/browser/webdata_services/web_data_service_factory.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +void EnsureBrowserStateKeyedServiceFactoriesBuilt() { + autofill::PersonalDataManagerFactory::GetInstance(); + ConsentAuditorFactory::GetInstance(); + ios::AccountConsistencyServiceFactory::GetInstance(); + ios::BookmarkModelFactory::GetInstance(); + ios::BookmarkUndoServiceFactory::GetInstance(); + ios::FaviconServiceFactory::GetInstance(); + ios::HistoryServiceFactory::GetInstance(); + ios::TemplateURLServiceFactory::GetInstance(); + ios::WebDataServiceFactory::GetInstance(); + IdentityManagerFactory::GetInstance(); + IOSChromePasswordStoreFactory::GetInstance(); + IOSChromeProfileInvalidationProviderFactory::GetInstance(); + IOSUserEventServiceFactory::GetInstance(); + ModelTypeStoreServiceFactory::GetInstance(); + ProfileSyncServiceFactory::GetInstance(); + ReadingListModelFactory::GetInstance(); + SessionSyncServiceFactory::GetInstance(); + SyncSetupServiceFactory::GetInstance(); +} diff --git a/chromium_src/ios/chrome/browser/prefs/BUILD.gn b/chromium_src/ios/chrome/browser/prefs/BUILD.gn new file mode 100644 index 000000000000..2eff57540b81 --- /dev/null +++ b/chromium_src/ios/chrome/browser/prefs/BUILD.gn @@ -0,0 +1,10 @@ +# 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/. + +group("prefs") { + deps = [ + "//brave/components/brave_sync:prefs", + ] +} diff --git a/chromium_src/ios/chrome/browser/prefs/browser_prefs.mm b/chromium_src/ios/chrome/browser/prefs/browser_prefs.mm new file mode 100644 index 000000000000..e5e747dadb01 --- /dev/null +++ b/chromium_src/ios/chrome/browser/prefs/browser_prefs.mm @@ -0,0 +1,13 @@ +/* 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/components/brave_sync/brave_sync_prefs.h" + +void BraveRegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) { + brave_sync::Prefs::RegisterProfilePrefs(registry); +} + +#define BRAVE_REGISTER_BROWSER_STATE_PREFS BraveRegisterBrowserStatePrefs(registry); +#include "../../../../../../ios/chrome/browser/prefs/browser_prefs.mm" diff --git a/chromium_src/ios/chrome/browser/signin/about_signin_internals_factory.cc b/chromium_src/ios/chrome/browser/signin/about_signin_internals_factory.cc new file mode 100644 index 000000000000..688b259276e5 --- /dev/null +++ b/chromium_src/ios/chrome/browser/signin/about_signin_internals_factory.cc @@ -0,0 +1,44 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/signin/about_signin_internals_factory.h" + +#include "base/no_destructor.h" +#include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/signin/core/browser/about_signin_internals.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" + +namespace ios { + +AboutSigninInternalsFactory::AboutSigninInternalsFactory() + : BrowserStateKeyedServiceFactory( + "AboutSigninInternals", + BrowserStateDependencyManager::GetInstance()) {} + +AboutSigninInternalsFactory::~AboutSigninInternalsFactory() {} + +// static +AboutSigninInternals* AboutSigninInternalsFactory::GetForBrowserState( + ChromeBrowserState* browser_state) { + return static_cast( + GetInstance()->GetServiceForBrowserState(browser_state, true)); +} + +// static +AboutSigninInternalsFactory* AboutSigninInternalsFactory::GetInstance() { + static base::NoDestructor instance; + return instance.get(); +} + +std::unique_ptr +AboutSigninInternalsFactory::BuildServiceInstanceFor( + web::BrowserState* context) const { + return nullptr; +} + +void AboutSigninInternalsFactory::RegisterBrowserStatePrefs( + user_prefs::PrefRegistrySyncable* user_prefs) {} + +} // namespace ios diff --git a/chromium_src/ios/chrome/browser/sync/profile_sync_service_factory.cc b/chromium_src/ios/chrome/browser/sync/profile_sync_service_factory.cc new file mode 100644 index 000000000000..ec78500ca18f --- /dev/null +++ b/chromium_src/ios/chrome/browser/sync/profile_sync_service_factory.cc @@ -0,0 +1,18 @@ +/* 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/sync/brave_profile_sync_service_delegate.h" +#include "brave/components/sync/driver/brave_sync_profile_sync_service.h" +#include "ios/chrome/browser/sync/device_info_sync_service_factory.h" + +#define BRAVE_BUILD_SERVICE_INSTANCE_FOR \ + std::make_unique( \ + std::move(init_params), \ + std::make_unique( \ + DeviceInfoSyncServiceFactory::GetForBrowserState(browser_state))); + +#include "../../../../../../ios/chrome/browser/sync/profile_sync_service_factory.cc" + +#undef BRAVE_BUILD_SERVICE_INSTANCE_FOR diff --git a/components/brave_sync/BUILD.gn b/components/brave_sync/BUILD.gn index 379bfebd72af..8ef5e2f076e2 100644 --- a/components/brave_sync/BUILD.gn +++ b/components/brave_sync/BUILD.gn @@ -8,6 +8,8 @@ declare_args() { brave_sync_endpoint = "" } +if (is_official_build) { assert(brave_sync_endpoint != "") } + config("brave_sync_config") { defines = [ "BRAVE_SYNC_ENDPOINT=\"$brave_sync_endpoint\"" diff --git a/components/sync/driver/brave_sync_profile_sync_service.cc b/components/sync/driver/brave_sync_profile_sync_service.cc index e887ec8e2534..9c84b640f8da 100644 --- a/components/sync/driver/brave_sync_profile_sync_service.cc +++ b/components/sync/driver/brave_sync_profile_sync_service.cc @@ -33,6 +33,7 @@ BraveProfileSyncService::BraveProfileSyncService( StopImpl(CLEAR_DATA); brave_sync_prefs_.SetSyncV1Migrated(true); } + profile_service_delegate_->set_profile_sync_service(this); } BraveProfileSyncService::~BraveProfileSyncService() { diff --git a/components/sync/driver/profile_sync_service_delegate.h b/components/sync/driver/profile_sync_service_delegate.h index 6bf5e826a57d..abe856bc22a9 100644 --- a/components/sync/driver/profile_sync_service_delegate.h +++ b/components/sync/driver/profile_sync_service_delegate.h @@ -8,13 +8,20 @@ namespace syncer { -class DeviceInfoSyncService; +class BraveProfileSyncService; class ProfileSyncServiceDelegate { public: virtual ~ProfileSyncServiceDelegate() {} virtual void SuspendDeviceObserverForOwnReset() = 0; virtual void ResumeDeviceObserver() = 0; + + void set_profile_sync_service(BraveProfileSyncService* profile_sync_service) { + profile_sync_service_ = profile_sync_service; + } + + protected: + BraveProfileSyncService* profile_sync_service_; }; } // namespace syncer diff --git a/ios/CPPLINT.cfg b/ios/CPPLINT.cfg new file mode 100644 index 000000000000..5aa0b0a7c46d --- /dev/null +++ b/ios/CPPLINT.cfg @@ -0,0 +1,2 @@ +# ios/app/brave_core_main.h:20: Using C-style cast. Use reinterpret_cast(...) instead [readability/casting] [4] ?? +filter=-readability/casting diff --git a/ios/app/BUILD.gn b/ios/app/BUILD.gn new file mode 100644 index 000000000000..4fa82671aecb --- /dev/null +++ b/ios/app/BUILD.gn @@ -0,0 +1,47 @@ +# 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/. + +import("//build/config/ios/rules.gni") +import("//ios/build/config.gni") + +source_set("app") { + configs += [ "//build/config/compiler:enable_arc" ] + + sources = [ + "brave_core_main.h", + "brave_core_main.mm", + "brave_main_delegate.h", + "brave_main_delegate.mm", + ] + + deps = [ + "//base", + "//brave/common:pref_names", + "//brave/components/brave_sync:constants", + "//brave/ios/browser", + "//components/browser_sync", + "//components/sync/driver", + "//components/sync/base", + "//ios/chrome/app:app_internal", + "//ios/chrome/app/startup:startup_basic", + "//ios/chrome/app/startup:startup", + "//ios/chrome/app:tests_fake_hook", + "//ios/chrome/browser", + "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/providers:provider_factory", + "//ios/chrome/common", + "//ios/public/provider/chrome/browser", + "//ios/web/public/init", + ] + + deps += [ + "//ios/third_party/material_components_ios:material_components_ios+link", + ] + + frameworks = [ + "Foundation.framework", + "UIKit.framework", + ] +} diff --git a/ios/app/brave_core_main.h b/ios/app/brave_core_main.h new file mode 100644 index 000000000000..2590403e00ff --- /dev/null +++ b/ios/app/brave_core_main.h @@ -0,0 +1,28 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_APP_BRAVE_CORE_MAIN_H_ +#define BRAVE_IOS_APP_BRAVE_CORE_MAIN_H_ + +#import + +NS_ASSUME_NONNULL_BEGIN + +OBJC_EXPORT +@interface BraveCoreMain : NSObject + +- (instancetype)init; + +- (instancetype)initWithSyncServiceURL:(NSString*)syncServiceURL; + +- (void)scheduleLowPriorityStartupTasks; + +- (void)setUserAgent:(NSString*)userAgent; + +@end + +NS_ASSUME_NONNULL_END + +#endif // BRAVE_IOS_APP_BRAVE_CORE_MAIN_H_ diff --git a/ios/app/brave_core_main.mm b/ios/app/brave_core_main.mm new file mode 100644 index 000000000000..fd1775559acb --- /dev/null +++ b/ios/app/brave_core_main.mm @@ -0,0 +1,109 @@ +/* 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/. */ + +#import "brave/ios/app/brave_core_main.h" + +#import + +#include "base/compiler_specific.h" +#include "base/strings/sys_string_conversions.h" +#include "brave/ios/app/brave_main_delegate.h" +#import "brave/ios/browser/brave_web_client.h" +#include "ios/chrome/app/startup/provider_registration.h" +#import "ios/chrome/app/startup_tasks.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#include "ios/public/provider/chrome/browser/chrome_browser_provider.h" +#include "ios/web/public/init/web_main.h" + +@interface BraveCoreMain () { + std::unique_ptr _webClient; + std::unique_ptr _delegate; + std::unique_ptr _webMain; + ChromeBrowserState* _mainBrowserState; +} +@end + +@implementation BraveCoreMain + +- (instancetype)init { + return [self initWithSyncServiceURL:@""]; +} + +- (instancetype)initWithSyncServiceURL:(NSString*)syncServiceURL { + if ((self = [super init])) { + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onAppEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onAppEnterForeground:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onAppWillTerminate:) + name:UIApplicationWillTerminateNotification + object:nil]; + + // Register all providers before calling any Chromium code. + [ProviderRegistration registerProviders]; + + _webClient.reset(new BraveWebClient()); + web::SetWebClient(_webClient.get()); + + _delegate.reset(new BraveMainDelegate()); + _delegate->SetSyncServiceURL(base::SysNSStringToUTF8(syncServiceURL)); + + web::WebMainParams params(_delegate.get()); + _webMain = std::make_unique(std::move(params)); + + ios::GetChromeBrowserProvider()->Initialize(); + + ios::ChromeBrowserStateManager* browserStateManager = + GetApplicationContext()->GetChromeBrowserStateManager(); + ChromeBrowserState* chromeBrowserState = + browserStateManager->GetLastUsedBrowserState(); + _mainBrowserState = chromeBrowserState; + } + return self; +} + +- (void)onAppEnterBackground:(NSNotification*)notification { + auto* context = GetApplicationContext(); + if (context) + context->OnAppEnterBackground(); +} + +- (void)onAppEnterForeground:(NSNotification*)notification { + auto* context = GetApplicationContext(); + if (context) + context->OnAppEnterForeground(); +} + +- (void)onAppWillTerminate:(NSNotification*)notification { + _webMain.reset(); +} + +- (void)scheduleLowPriorityStartupTasks { + [StartupTasks scheduleDeferredBrowserStateInitialization:_mainBrowserState]; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + _mainBrowserState = nullptr; + _webMain.reset(); + _delegate.reset(); + _webClient.reset(); +} + +- (void)setUserAgent:(NSString*)userAgent { + _webClient->SetUserAgent(base::SysNSStringToUTF8(userAgent)); +} + +@end diff --git a/ios/app/brave_main_delegate.h b/ios/app/brave_main_delegate.h new file mode 100644 index 000000000000..c8bf85085617 --- /dev/null +++ b/ios/app/brave_main_delegate.h @@ -0,0 +1,32 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_APP_BRAVE_MAIN_DELEGATE_H_ +#define BRAVE_IOS_APP_BRAVE_MAIN_DELEGATE_H_ + +#include + +#include "base/macros.h" +#include "ios/chrome/app/startup/ios_chrome_main_delegate.h" + +class BraveWebClient; + +class BraveMainDelegate : public IOSChromeMainDelegate { + public: + BraveMainDelegate(); + ~BraveMainDelegate() override; + + void SetSyncServiceURL(const std::string& url); + + protected: + // web::WebMainDelegate implementation: + void BasicStartupComplete() override; + + private: + std::string brave_sync_service_url_; + DISALLOW_COPY_AND_ASSIGN(BraveMainDelegate); +}; + +#endif // BRAVE_IOS_APP_BRAVE_MAIN_DELEGATE_H_ diff --git a/ios/app/brave_main_delegate.mm b/ios/app/brave_main_delegate.mm new file mode 100644 index 000000000000..e4ad016c0a51 --- /dev/null +++ b/ios/app/brave_main_delegate.mm @@ -0,0 +1,61 @@ +/* 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/ios/app/brave_main_delegate.h" + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/mac/bundle_locations.h" +#include "base/base_paths.h" +#include "base/path_service.h" +#include "components/sync/driver/sync_driver_switches.h" +#include "components/sync/base/model_type.h" +#include "components/browser_sync/browser_sync_switches.h" +#include "components/sync/base/sync_base_switches.h" +#include "ios/chrome/browser/chrome_switches.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { +const char kBraveSyncServiceURL[] = BRAVE_SYNC_ENDPOINT; +} // namespace + +BraveMainDelegate::BraveMainDelegate() : brave_sync_service_url_(kBraveSyncServiceURL) { + base::FilePath path; + base::PathService::Get(base::DIR_MODULE, &path); + base::mac::SetOverrideFrameworkBundlePath(path); + base::mac::SetOverrideOuterBundlePath(path); +} + +BraveMainDelegate::~BraveMainDelegate() {} + +void BraveMainDelegate::SetSyncServiceURL(const std::string& url) { + brave_sync_service_url_ = url.empty() ? std::string(kBraveSyncServiceURL) : url; +} + +void BraveMainDelegate::BasicStartupComplete() { + auto* command_line(base::CommandLine::ForCurrentProcess()); + + syncer::ModelTypeSet disabledTypes = syncer::ModelTypeSet( + syncer::TYPED_URLS, + // syncer::PASSWORDS, + syncer::PROXY_TABS, + syncer::AUTOFILL, + // syncer::PREFERENCES, + syncer::READING_LIST, + syncer::USER_CONSENTS); + + command_line->RemoveSwitch(switches::kDisableSyncTypes); + command_line->AppendSwitchASCII(switches::kDisableSyncTypes, syncer::ModelTypeSetToString(disabledTypes)); + command_line->AppendSwitch(switches::kDisableEnterprisePolicy); + + // Brave's sync protocol does not use the sync service url + command_line->AppendSwitchASCII(switches::kSyncServiceURL, + brave_sync_service_url_.c_str()); + + IOSChromeMainDelegate::BasicStartupComplete(); +} diff --git a/ios/app/headers.gni b/ios/app/headers.gni new file mode 100644 index 000000000000..123ad68a60c6 --- /dev/null +++ b/ios/app/headers.gni @@ -0,0 +1,13 @@ +# 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/. + +brave_core_public_headers = [ + "//brave/ios/app/brave_core_main.h", + "//brave/ios/browser/api/bookmarks/brave_bookmarks_api.h", + "//brave/ios/browser/api/bookmarks/brave_bookmarks_observer.h", + "//brave/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.h", + "//brave/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.h", + "//brave/ios/browser/api/sync/brave_sync_api.h", +] diff --git a/ios/browser/BUILD.gn b/ios/browser/BUILD.gn new file mode 100644 index 000000000000..d95f17cf36df --- /dev/null +++ b/ios/browser/BUILD.gn @@ -0,0 +1,42 @@ +# 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/. + +import("//build/config/ios/rules.gni") +import("//ios/build/config.gni") + +source_set("browser") { + configs += [ "//build/config/compiler:enable_arc" ] + + sources = [ + "brave_web_client.h", + "brave_web_client.mm", + "brave_web_main_parts.h", + "brave_web_main_parts.mm", + ] + + deps = [ + "api/bookmarks", + "api/bookmarks/importer", + "api/bookmarks/exporter", + "api/sync", + "metrics", + "//base", + "//brave/browser/sync", + "//brave/chromium_src/ios/chrome/browser/prefs", + "//components/flags_ui", + "//components/metrics_services_manager", + "//components/variations/service", + "//ios/chrome/browser", + "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/browser_state:browser_state_impl", + "//ios/chrome/browser/flags", + "//ios/chrome/browser:browser_impl", + "//ios/chrome/browser:chrome_paths", + "//ios/web/public", + "//ios/web/public/init", + "//ios/web/public/thread", + "//ui/base", + ] +} diff --git a/ios/browser/api/bookmarks/BUILD.gn b/ios/browser/api/bookmarks/BUILD.gn new file mode 100644 index 000000000000..564e3b9e9db9 --- /dev/null +++ b/ios/browser/api/bookmarks/BUILD.gn @@ -0,0 +1,38 @@ +# 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/. + +import("//build/config/ios/rules.gni") +import("//ios/build/config.gni") + +source_set("bookmarks") { + configs += [ "//build/config/compiler:enable_arc" ] + + sources = [ + "brave_bookmarks_api.h", + "brave_bookmarks_api.mm", + "brave_bookmarks_observer.h", + "brave_bookmarks_observer.mm", + ] + + deps = [ + "//base", + "//components/bookmarks/browser", + "//components/prefs:prefs", + "//components/undo", + "//components/user_prefs:user_prefs", + "//ios/chrome/browser", + "//ios/chrome/browser/bookmarks", + "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/ui/bookmarks:bookmarks", + "//ios/chrome/browser/undo", + "//ios/web/public/thread", + "//net", + "//url", + ] + + frameworks = [ + "Foundation.framework", + ] +} diff --git a/ios/browser/api/bookmarks/brave_bookmarks_api.h b/ios/browser/api/bookmarks/brave_bookmarks_api.h new file mode 100644 index 000000000000..f77941d05085 --- /dev/null +++ b/ios/browser/api/bookmarks/brave_bookmarks_api.h @@ -0,0 +1,141 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_BRAVE_BOOKMARKS_API_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_BRAVE_BOOKMARKS_API_H_ + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, BookmarksNodeType) { + BookmarksNodeTypeUrl, + BookmarksNodeTypeFolder, + BookmarksNodeTypeBookmarkBar, + BookmarksNodeTypeOtherNode, + BookmarksNodeTypeMobile +}; + +typedef NS_ENUM(NSUInteger, BookmarksNodeFaviconState) { + BookmarksNodeFaviconStateInvalidFavIcon, + BookmarksNodeFaviconStateLoadingFavIcon, + BookmarksNodeFaviconStateLoadedFavIcon, +}; + +@protocol BookmarkModelObserver; +@protocol BookmarkModelListener; + +@class IOSBookmarkNode; + +OBJC_EXPORT +@interface BookmarkFolder : NSObject +@property(nonatomic, readonly) IOSBookmarkNode* bookmarkNode; +@property(nonatomic, readonly) NSInteger indentationLevel; +@end + +NS_SWIFT_NAME(BookmarkNode) +OBJC_EXPORT +@interface IOSBookmarkNode : NSObject +@property(class, nonatomic, copy, readonly) NSString* rootNodeGuid; +@property(class, nonatomic, copy, readonly) NSString* bookmarkBarNodeGuid; +@property(class, nonatomic, copy, readonly) NSString* otherBookmarksNodeGuid; +@property(class, nonatomic, copy, readonly) NSString* mobileBookmarksNodeGuid; +@property(class, nonatomic, copy, readonly) NSString* managedNodeGuid; + +@property(nonatomic, readonly) bool isPermanentNode; + +@property(nonatomic, readonly) NSUInteger nodeId; +@property(nonatomic, copy, readonly) NSString* guid; +@property(nonatomic, nullable, copy) NSURL* url; +@property(nonatomic, nullable, copy, readonly) NSURL* iconUrl; +@property(nonatomic, nullable, copy, readonly) UIImage* icon; + +@property(nonatomic, readonly) BookmarksNodeType type; +@property(nonatomic, copy) NSDate* dateAdded; +@property(nonatomic, copy) NSDate* dateFolderModified; + +@property(nonatomic, readonly) bool isFolder; +@property(nonatomic, readonly) bool isUrl; +@property(nonatomic, readonly) bool isFavIconLoaded; +@property(nonatomic, readonly) bool isFavIconLoading; +@property(nonatomic, readonly) bool isVisible; +@property(nonatomic, readonly) bool isValid; + +@property(nonatomic, readonly) NSString* titleUrlNodeTitle; +@property(nonatomic, nullable, readonly) NSURL* titleUrlNodeUrl; + +@property(nonatomic, nullable, readonly) IOSBookmarkNode* parent; +@property(nonatomic, readonly) NSArray* children; +@property(nonatomic, readonly) NSArray* nestedChildFolders; +@property(nonatomic, readonly) NSUInteger childCount; + +- (nullable IOSBookmarkNode*)childAtIndex:(NSUInteger)index; +- (NSArray*)nestedChildFoldersFiltered:(BOOL(^)(BookmarkFolder*))included + NS_SWIFT_NAME(nestedChildFolders(where:)); + +- (void)setTitle:(NSString*)title; +- (bool)getMetaInfo:(NSString*)key value:(NSString* _Nonnull* _Nullable)value; +- (void)setMetaInfo:(NSString*)key value:(NSString*)value; +- (void)deleteMetaInfo:(NSString*)key; + +- (nullable IOSBookmarkNode*)addChildFolderWithTitle:(NSString*)title; +- (nullable IOSBookmarkNode*)addChildBookmarkWithTitle:(NSString*)title + url:(NSURL*)url; + +- (void)moveToParent:(nonnull IOSBookmarkNode*)parent; +- (void)moveToParent:(nonnull IOSBookmarkNode*)parent index:(NSUInteger)index; +- (NSInteger)indexOfChild:(nonnull IOSBookmarkNode*)child; +- (bool)hasAncestor:(nonnull IOSBookmarkNode*)parent; + +- (instancetype)initWithTitle:(NSString*)title + id:(int64_t)id + guid:(NSString* _Nullable)guid + url:(NSURL* _Nullable)url + dateAdded:(NSDate* _Nullable)dateAdded + dateModified:(NSDate* _Nullable)dateModified + children: + (NSArray* _Nullable)children; +@end + +NS_SWIFT_NAME(BraveBookmarksAPI) +OBJC_EXPORT +@interface BraveBookmarksAPI : NSObject +@property(class, readonly, getter = sharedBookmarksAPI) + BraveBookmarksAPI* shared; +@property(nonatomic, nullable, readonly) IOSBookmarkNode* rootNode; +@property(nonatomic, nullable, readonly) IOSBookmarkNode* otherNode; +@property(nonatomic, nullable, readonly) IOSBookmarkNode* mobileNode; +@property(nonatomic, nullable, readonly) IOSBookmarkNode* desktopNode; +@property(nonatomic, readonly) bool isLoaded; +@property(nonatomic, readonly) bool editingEnabled; + +- (id)addObserver:(id)observer; +- (void)removeObserver:(id)observer; + +- (nullable IOSBookmarkNode*)createFolderWithTitle:(NSString*)title; +- (nullable IOSBookmarkNode*)createFolderWithParent:(IOSBookmarkNode*)parent + title:(NSString*)title; + +- (nullable IOSBookmarkNode*)createBookmarkWithTitle:(NSString*)title + url:(NSURL*)url; +- (nullable IOSBookmarkNode*)createBookmarkWithParent:(IOSBookmarkNode*)parent + title:(NSString*)title + withUrl:(NSURL*)url; + +- (nullable IOSBookmarkNode*)getNodeById:(NSInteger)nodeId; + +- (void)removeBookmark:(IOSBookmarkNode*)bookmark; +- (void)removeAll; + +- (NSArray*)searchWithQuery:(NSString*)query + maxCount:(NSUInteger)maxCount; + +- (void)undo; +@end + +NS_ASSUME_NONNULL_END + +#endif // BRAVE_IOS_BROWSER_API_BOOKMARKS_BRAVE_BOOKMARKS_API_H_ diff --git a/ios/browser/api/bookmarks/brave_bookmarks_api.mm b/ios/browser/api/bookmarks/brave_bookmarks_api.mm new file mode 100644 index 000000000000..86bf848a723d --- /dev/null +++ b/ios/browser/api/bookmarks/brave_bookmarks_api.mm @@ -0,0 +1,653 @@ +/* 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/ios/browser/api/bookmarks/brave_bookmarks_api.h" + +#include "base/compiler_specific.h" +#include "base/containers/adapters.h" +#include "base/guid.h" +#include "base/strings/sys_string_conversions.h" +#include "brave/ios/browser/api/bookmarks/brave_bookmarks_observer.h" +#include "components/bookmarks/browser/bookmark_model.h" +#include "components/bookmarks/browser/bookmark_node.h" +#include "components/bookmarks/browser/bookmark_utils.h" +#include "components/bookmarks/common/bookmark_pref_names.h" +#include "components/prefs/pref_service.h" +#include "components/undo/bookmark_undo_service.h" +#include "components/undo/undo_manager.h" +#include "components/user_prefs/user_prefs.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#include "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" +#include "ios/chrome/browser/undo/bookmark_undo_service_factory.h" +#include "ios/web/public/thread/web_thread.h" +#import "net/base/mac/url_conversions.h" +#include "url/gurl.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// Used from the iOS/Swift side only.. +@implementation BookmarkFolder +- (instancetype)initWithNode:(IOSBookmarkNode*)node + indentationLevel:(NSInteger)indentationLevel { + if ((self = [super init])) { + _bookmarkNode = node; + _indentationLevel = indentationLevel; + } + return self; +} +@end + +@interface IOSBookmarkNode () { + const bookmarks::BookmarkNode* node_; + bookmarks::BookmarkModel* model_; // UNOWNED + bool owned_; +} +@end + +@implementation IOSBookmarkNode + +- (instancetype)initWithNode:(const bookmarks::BookmarkNode*)node + model:(bookmarks::BookmarkModel*)model { + if ((self = [super init])) { + node_ = node; + model_ = model; + owned_ = false; + } + return self; +} + +- (instancetype)initWithTitle:(NSString*)title + id:(int64_t)id + guid:(NSString*)guid + url:(NSURL*)url + dateAdded:(NSDate*)dateAdded + dateModified:(NSDate*)dateModified + children:(NSArray*)children { + if ((self = [super init])) { + // Only in a NEWER version of Chromium, they have `base::GUID` + std::string guid_; // base::GUID guid_ = base::GUID(); + int64_t id_ = static_cast(id); + + if ([guid length] > 0) { + DCHECK(base::IsValidGUID(base::SysNSStringToUTF16(guid))); + guid_ = [guid UTF8String]; + } else { + guid_ = base::GenerateGUID(); + } + + GURL gurl_ = net::GURLWithNSURL(url); + bookmarks::BookmarkNode* node = + new bookmarks::BookmarkNode(id_, guid_, gurl_); + node->SetTitle(base::SysNSStringToUTF16(title)); + + if (dateAdded) { + node->set_date_added( + base::Time::FromDoubleT([dateAdded timeIntervalSince1970])); + } + + if (dateModified) { + node->set_date_folder_modified( + base::Time::FromDoubleT([dateModified timeIntervalSince1970])); + } + + for (IOSBookmarkNode* child : children) { + DCHECK(child->owned_); // Bookmark must be owned and non-const. IE: + // Allocated from iOS/Swift. + child->owned_ = false; + child->node_ = node->Add(std::unique_ptr( + const_cast(child->node_))); + } + + node_ = node; + model_ = nil; + owned_ = true; + } + return self; +} + +- (void)dealloc { + if (owned_) { + // All Objective-C++ class pointers are reference counted. + // No need for copy or move constructor & assignment operators. + // They're automatic RAII.. So we can safely delete an owned raw pointer + // here. + delete node_; + node_ = nullptr; + owned_ = false; + } + node_ = nullptr; + model_ = nullptr; +} + ++ (NSString*)rootNodeGuid { + return base::SysUTF8ToNSString(bookmarks::BookmarkNode::kRootNodeGuid); +} + ++ (NSString*)bookmarkBarNodeGuid { + return base::SysUTF8ToNSString(bookmarks::BookmarkNode::kBookmarkBarNodeGuid); +} + ++ (NSString*)otherBookmarksNodeGuid { + return base::SysUTF8ToNSString( + bookmarks::BookmarkNode::kOtherBookmarksNodeGuid); +} + ++ (NSString*)mobileBookmarksNodeGuid { + return base::SysUTF8ToNSString( + bookmarks::BookmarkNode::kMobileBookmarksNodeGuid); +} + ++ (NSString*)managedNodeGuid { + return base::SysUTF8ToNSString(bookmarks::BookmarkNode::kManagedNodeGuid); +} + +- (bool)isPermanentNode { + DCHECK(node_); + return node_->is_permanent_node(); +} + +- (void)setTitle:(NSString*)title { + DCHECK(node_); + DCHECK(model_); + model_->SetTitle(node_, base::SysNSStringToUTF16(title)); +} + +- (NSUInteger)nodeId { + DCHECK(node_); + return node_->id(); +} + +- (NSString*)guid { + DCHECK(node_); + return base::SysUTF8ToNSString(node_->guid()); +} + +- (NSURL*)url { + DCHECK(node_); + return net::NSURLWithGURL(node_->url()); +} + +- (void)setUrl:(NSURL*)url { + DCHECK(node_); + DCHECK(model_); + model_->SetURL(node_, net::GURLWithNSURL(url)); +} + +- (NSURL*)iconUrl { + DCHECK(node_); + const GURL* url = node_->icon_url(); + return url ? net::NSURLWithGURL(*url) : nullptr; +} + +- (UIImage*)icon { + DCHECK(node_); + DCHECK(model_); + gfx::Image icon = model_->GetFavicon(node_); + return icon.IsEmpty() ? nullptr : icon.ToUIImage(); +} + +- (BookmarksNodeType)type { + DCHECK(node_); + switch (node_->type()) { + case bookmarks::BookmarkNode::URL: + return BookmarksNodeTypeUrl; + case bookmarks::BookmarkNode::FOLDER: + return BookmarksNodeTypeFolder; + case bookmarks::BookmarkNode::BOOKMARK_BAR: + return BookmarksNodeTypeBookmarkBar; + case bookmarks::BookmarkNode::OTHER_NODE: + return BookmarksNodeTypeOtherNode; + case bookmarks::BookmarkNode::MOBILE: + return BookmarksNodeTypeMobile; + } + return BookmarksNodeTypeMobile; +} + +- (NSDate*)dateAdded { + DCHECK(node_); + return [NSDate dateWithTimeIntervalSince1970:node_->date_added().ToDoubleT()]; +} + +- (void)setDateAdded:(NSDate*)date { + DCHECK(node_); + DCHECK(model_); + model_->SetDateAdded(node_, + base::Time::FromDoubleT([date timeIntervalSince1970])); +} + +- (NSDate*)dateFolderModified { + DCHECK(node_); + return [NSDate + dateWithTimeIntervalSince1970:node_->date_folder_modified().ToDoubleT()]; +} + +- (void)setDateFolderModified:(NSDate*)date { + DCHECK(node_); + DCHECK(model_); + model_->SetDateFolderModified( + node_, base::Time::FromDoubleT([date timeIntervalSince1970])); +} + +- (bool)isFolder { + DCHECK(node_); + return node_->is_folder(); +} + +- (bool)isUrl { + DCHECK(node_); + return node_->is_url(); +} + +- (bool)isFavIconLoaded { + DCHECK(node_); + return node_->is_favicon_loaded(); +} + +- (bool)isFavIconLoading { + DCHECK(node_); + return node_->is_favicon_loading(); +} + +- (bool)isVisible { + DCHECK(node_); + return node_->IsVisible(); +} + +- (bool)isValid { + return node_ && model_; +} + +- (bool)getMetaInfo:(NSString*)key value:(NSString**)value { + DCHECK(node_); + std::string value_; + bool result = node_->GetMetaInfo(base::SysNSStringToUTF8(key), &value_); + if (value) { + *value = base::SysUTF8ToNSString(value_); + } + return result; +} + +- (void)setMetaInfo:(NSString*)key value:(NSString*)value { + DCHECK(node_); + DCHECK(model_); + model_->SetNodeMetaInfo(node_, base::SysNSStringToUTF8(key), + base::SysNSStringToUTF8(value)); +} + +- (void)deleteMetaInfo:(NSString*)key { + DCHECK(node_); + DCHECK(model_); + return model_->DeleteNodeMetaInfo(node_, base::SysNSStringToUTF8(key)); +} + +- (NSString*)titleUrlNodeTitle { + DCHECK(node_); + return base::SysUTF16ToNSString(node_->GetTitledUrlNodeTitle()); +} + +- (NSURL*)titleUrlNodeUrl { + DCHECK(node_); + return net::NSURLWithGURL(node_->GetTitledUrlNodeUrl()); +} + +- (IOSBookmarkNode*)parent { + DCHECK(node_); + const bookmarks::BookmarkNode* parent_ = node_->parent(); + if (parent_) { + return [[IOSBookmarkNode alloc] initWithNode:parent_ model:model_]; + } + return nil; +} + +- (NSArray*)children { + DCHECK(node_); + NSMutableArray* result = [[NSMutableArray alloc] init]; + for (const auto& child : node_->children()) { + [result addObject:[[IOSBookmarkNode alloc] initWithNode:child.get() + model:model_]]; + } + return result; +} + +- (NSArray*)nestedChildFolders { + // Returns a list of ALL nested folders + return [self nestedChildFoldersFiltered:^{ return true; }]; +} + +- (NSUInteger)childCount { + DCHECK(node_); + return node_->GetTotalNodeCount() - 1; +} + +- (IOSBookmarkNode*)childAtIndex:(NSUInteger)index { + DCHECK(node_); + const auto& children = node_->children(); + if (static_cast(index) < children.size()) { + return [[IOSBookmarkNode alloc] initWithNode:children[index].get() + model:model_]; + ; + } + return nil; +} + +// Retrieves a list of nested child folders filtered by the predicate |included| +// iOS calls it like: `self.nestedChildFolders(where: { return some_condition })` +- (NSArray*)nestedChildFoldersFiltered:(BOOL(^)(BookmarkFolder*))included { + DCHECK(node_); + + std::vector bookmarks = {node_}; + + base::stack> stack; + for (const bookmarks::BookmarkNode* bookmark : base::Reversed(bookmarks)) { + stack.emplace(bookmark, 0); + } + + NSMutableArray* result = [[NSMutableArray alloc] init]; + while (!stack.empty()) { + const bookmarks::BookmarkNode* node = stack.top().first; + std::int32_t depth = stack.top().second; + stack.pop(); + + IOSBookmarkNode* ios_bookmark_node = + [[IOSBookmarkNode alloc] initWithNode:node model:model_]; + BookmarkFolder* ios_bookmark_folder = [[BookmarkFolder alloc] initWithNode:ios_bookmark_node + indentationLevel:depth]; + + if (included(ios_bookmark_folder)) { + // Store the folder + its depth + [result addObject:ios_bookmark_folder]; + + bookmarks.clear(); + for (const auto& child : node->children()) { + if (child->is_folder()) { + ios_bookmark_node = [[IOSBookmarkNode alloc] initWithNode:child.get() model:model_]; + ios_bookmark_folder = [[BookmarkFolder alloc] initWithNode:ios_bookmark_node + indentationLevel:depth + 1]; + if (included(ios_bookmark_folder)) { + bookmarks.push_back(child.get()); + } + } + } + } + + for (const auto* bookmark : base::Reversed(bookmarks)) { + stack.emplace(bookmark, depth + 1); + } + } + + return result; +} + +- (IOSBookmarkNode*)addChildFolderWithTitle:(NSString*)title { + DCHECK(node_); + DCHECK(model_); + if ([self isFolder]) { + const bookmarks::BookmarkNode* node = model_->AddFolder( + node_, node_->children().size(), base::SysNSStringToUTF16(title)); + return [[IOSBookmarkNode alloc] initWithNode:node model:model_]; + } + return nil; +} + +- (IOSBookmarkNode*)addChildBookmarkWithTitle:(NSString*)title url:(NSURL*)url { + DCHECK(node_); + DCHECK(model_); + if ([self isFolder]) { + const bookmarks::BookmarkNode* node = model_->AddURL( + node_, node_->children().size(), base::SysNSStringToUTF16(title), + net::GURLWithNSURL(url)); + return [[IOSBookmarkNode alloc] initWithNode:node model:model_]; + } + return nil; +} + +- (void)moveToParent:(IOSBookmarkNode*)parent { + DCHECK(node_); + DCHECK(model_); + if ([parent isFolder]) { + model_->Move(node_, parent->node_, parent->node_->children().size()); + } +} + +- (void)moveToParent:(IOSBookmarkNode*)parent index:(NSUInteger)index { + DCHECK(node_); + DCHECK(model_); + if ([parent isFolder]) { + model_->Move(node_, parent->node_, index); + } +} + +- (NSInteger)indexOfChild:(IOSBookmarkNode*)child { + DCHECK(node_); + return node_->GetIndexOf(child->node_); +} + +- (bool)hasAncestor:(IOSBookmarkNode*)parent { + DCHECK(node_); + return node_->HasAncestor(parent->node_); +} + +- (void)remove { + DCHECK(node_); + DCHECK(model_); + model_->Remove(node_); + node_ = nil; + model_ = nil; +} + +- (const bookmarks::BookmarkNode*)getNode { + return node_; +} + +- (void)setNativeParent:(bookmarks::BookmarkNode*)parent { + DCHECK(owned_); + owned_ = false; + node_ = parent->Add(std::unique_ptr( + const_cast(node_))); +} + +@end + +@interface BraveBookmarksAPI () { + bookmarks::BookmarkModel* bookmark_model_; // NOT OWNED + BookmarkUndoService* bookmark_undo_service_; // NOT OWNED +} +@end + +@implementation BraveBookmarksAPI ++ (instancetype)sharedBookmarksAPI { + static BraveBookmarksAPI* instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[BraveBookmarksAPI alloc] init]; + }); + return instance; +} + +- (instancetype)init { + if ((self = [super init])) { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + ios::ChromeBrowserStateManager* browserStateManager = + GetApplicationContext()->GetChromeBrowserStateManager(); + ChromeBrowserState* browserState = + browserStateManager->GetLastUsedBrowserState(); + bookmark_model_ = + ios::BookmarkModelFactory::GetForBrowserState(browserState); + bookmark_undo_service_ = + ios::BookmarkUndoServiceFactory::GetForBrowserState(browserState); + } + return self; +} + +- (void)dealloc { + bookmark_model_ = nil; + bookmark_undo_service_ = nil; +} + +- (IOSBookmarkNode*)rootNode { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + const bookmarks::BookmarkNode* node = bookmark_model_->root_node(); + if (node) { + return [[IOSBookmarkNode alloc] initWithNode:node model:bookmark_model_]; + } + return nil; +} + +- (IOSBookmarkNode*)otherNode { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + const bookmarks::BookmarkNode* node = bookmark_model_->other_node(); + if (node) { + return [[IOSBookmarkNode alloc] initWithNode:node model:bookmark_model_]; + } + return nil; +} + +- (IOSBookmarkNode*)mobileNode { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + const bookmarks::BookmarkNode* node = bookmark_model_->mobile_node(); + if (node) { + return [[IOSBookmarkNode alloc] initWithNode:node model:bookmark_model_]; + } + return nil; +} + +- (IOSBookmarkNode*)desktopNode { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + const bookmarks::BookmarkNode* node = bookmark_model_->bookmark_bar_node(); + if (node) { + return [[IOSBookmarkNode alloc] initWithNode:node model:bookmark_model_]; + } + return nil; +} + +- (bool)isLoaded { + return bookmark_model_->loaded(); +} + +- (id)addObserver:(id)observer { + return [[BookmarkModelListenerImpl alloc] init:observer + bookmarkModel:bookmark_model_]; +} + +- (void)removeObserver:(id)observer { + [observer destroy]; +} + +- (bool)editingEnabled { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + ios::ChromeBrowserStateManager* browserStateManager = + GetApplicationContext()->GetChromeBrowserStateManager(); + ChromeBrowserState* browserState = + browserStateManager->GetLastUsedBrowserState(); + + PrefService* prefs = user_prefs::UserPrefs::Get(browserState); + return prefs->GetBoolean(bookmarks::prefs::kEditBookmarksEnabled); +} + +- (IOSBookmarkNode*)createFolderWithTitle:(NSString*)title { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + if ([self mobileNode]) { + return [self createFolderWithParent:[self mobileNode] title:title]; + } + return nil; +} + +- (IOSBookmarkNode*)createFolderWithParent:(IOSBookmarkNode*)parent + title:(NSString*)title { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + DCHECK(parent); + const bookmarks::BookmarkNode* defaultFolder = [parent getNode]; + + const bookmarks::BookmarkNode* new_node = bookmark_model_->AddFolder( + defaultFolder, defaultFolder->children().size(), + base::SysNSStringToUTF16(title)); + if (new_node) { + return [[IOSBookmarkNode alloc] initWithNode:new_node + model:bookmark_model_]; + } + return nil; +} + +- (IOSBookmarkNode*)createBookmarkWithTitle:(NSString*)title url:(NSURL*)url { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + if ([self mobileNode]) { + return [self createBookmarkWithParent:[self mobileNode] + title:title + withUrl:url]; + } + return nil; +} + +- (IOSBookmarkNode*)createBookmarkWithParent:(IOSBookmarkNode*)parent + title:(NSString*)title + withUrl:(NSURL*)url { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + DCHECK(parent); + const bookmarks::BookmarkNode* defaultFolder = [parent getNode]; + + const bookmarks::BookmarkNode* new_node = bookmark_model_->AddURL( + defaultFolder, defaultFolder->children().size(), + base::SysNSStringToUTF16(title), net::GURLWithNSURL(url)); + if (new_node) { + return [[IOSBookmarkNode alloc] initWithNode:new_node + model:bookmark_model_]; + } + return nil; +} + +- (IOSBookmarkNode*)getNodeById:(NSInteger)nodeId { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + const bookmarks::BookmarkNode* node = bookmarks::GetBookmarkNodeByID( + bookmark_model_, static_cast(nodeId)); + if (node) { + return [[IOSBookmarkNode alloc] initWithNode:node model:bookmark_model_]; + } + return nil; +} + +- (void)removeBookmark:(IOSBookmarkNode*)bookmark { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + [bookmark remove]; +} + +- (void)removeAll { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + bookmark_model_->RemoveAllUserBookmarks(); +} + +- (NSArray*)searchWithQuery:(NSString*)query + maxCount:(NSUInteger)maxCount { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + DCHECK(bookmark_model_->loaded()); + bookmarks::QueryFields queryFields; + queryFields.word_phrase_query.reset( + new base::string16(base::SysNSStringToUTF16(query))); + std::vector results; + GetBookmarksMatchingProperties(bookmark_model_, queryFields, maxCount, + &results); + + NSMutableArray* nodes = [[NSMutableArray alloc] init]; + for (const bookmarks::BookmarkNode* bookmark : results) { + IOSBookmarkNode* node = + [[IOSBookmarkNode alloc] initWithNode:bookmark model:bookmark_model_]; + [nodes addObject:node]; + } + return nodes; +} + +- (void)undo { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + bookmark_undo_service_->undo_manager()->Undo(); +} + +- (bookmarks::BookmarkModel*)getModel { + return bookmark_model_; +} +@end diff --git a/ios/browser/api/bookmarks/brave_bookmarks_observer.h b/ios/browser/api/bookmarks/brave_bookmarks_observer.h new file mode 100644 index 000000000000..b5fcd06f5128 --- /dev/null +++ b/ios/browser/api/bookmarks/brave_bookmarks_observer.h @@ -0,0 +1,43 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_BRAVE_BOOKMARKS_OBSERVER_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_BRAVE_BOOKMARKS_OBSERVER_H_ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class IOSBookmarkNode; + +OBJC_EXPORT +@protocol BookmarkModelObserver +@optional +- (void)bookmarkModelLoaded; +- (void)bookmarkNodeChanged:(IOSBookmarkNode*)bookmarkNode; +- (void)bookmarkNodeChildrenChanged:(IOSBookmarkNode*)bookmarkNode; +- (void)bookmarkNode:(IOSBookmarkNode*)bookmarkNode + movedFromParent:(IOSBookmarkNode*)oldParent + toParent:(IOSBookmarkNode*)newParent; +- (void)bookmarkNodeDeleted:(IOSBookmarkNode*)node + fromFolder:(IOSBookmarkNode*)folder; +- (void)bookmarkModelRemovedAllNodes; +- (void)bookmarkNodeFaviconChanged:(IOSBookmarkNode*)bookmarkNode; +@end + +OBJC_EXPORT +@protocol BookmarkModelListener +- (void)destroy; +@end + +OBJC_EXPORT +@interface BookmarkModelListenerImpl : NSObject +- (instancetype)init:(id)observer + bookmarkModel:(void*)bookmarkModel; +@end + +NS_ASSUME_NONNULL_END + +#endif /* BRAVE_IOS_BROWSER_API_BOOKMARKS_BRAVE_BOOKMARKS_OBSERVER_H_ */ diff --git a/ios/browser/api/bookmarks/brave_bookmarks_observer.mm b/ios/browser/api/bookmarks/brave_bookmarks_observer.mm new file mode 100644 index 000000000000..4cce57694d35 --- /dev/null +++ b/ios/browser/api/bookmarks/brave_bookmarks_observer.mm @@ -0,0 +1,211 @@ +/* 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/ios/browser/api/bookmarks/brave_bookmarks_observer.h" + +#include + +#include "base/check.h" +#include "base/compiler_specific.h" +#include "base/notreached.h" +#include "brave/ios/browser/api/bookmarks/brave_bookmarks_api.h" +#include "components/bookmarks/browser/bookmark_model.h" +#include "components/bookmarks/browser/bookmark_model_observer.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface IOSBookmarkNode (Private) +- (instancetype)initWithNode:(const bookmarks::BookmarkNode*)node + model:(bookmarks::BookmarkModel*)model; +@end + +namespace brave { +namespace ios { +class BookmarkModelListener : public bookmarks::BookmarkModelObserver { + public: + explicit BookmarkModelListener(id observer, + bookmarks::BookmarkModel* model); + ~BookmarkModelListener() override; + + private: + void BookmarkModelLoaded(bookmarks::BookmarkModel* model, + bool ids_reassigned) override; + void BookmarkModelBeingDeleted(bookmarks::BookmarkModel* model) override; + void BookmarkNodeMoved(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* old_parent, + size_t old_index, + const bookmarks::BookmarkNode* new_parent, + size_t new_index) override; + void BookmarkNodeAdded(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + size_t index) override; + void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + size_t old_index, + const bookmarks::BookmarkNode* node, + const std::set& removed_urls) override; + void BookmarkNodeChanged(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) override; + void BookmarkNodeFaviconChanged(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) override; + void BookmarkNodeChildrenReordered( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) override; + void BookmarkAllUserNodesRemoved(bookmarks::BookmarkModel* model, + const std::set& removed_urls) override; + + __strong id observer_; + bookmarks::BookmarkModel* model_; // weak +}; + +BookmarkModelListener::BookmarkModelListener(id observer, + bookmarks::BookmarkModel* model) + : observer_(observer), model_(model) { + DCHECK(observer_); + DCHECK(model_); + model_->AddObserver(this); +} + +BookmarkModelListener::~BookmarkModelListener() { + DCHECK(model_); + model_->RemoveObserver(this); +} + +void BookmarkModelListener::BookmarkModelLoaded(bookmarks::BookmarkModel* model, + bool ids_reassigned) { + if ([observer_ respondsToSelector:@selector(bookmarkModelLoaded)]) { + [observer_ bookmarkModelLoaded]; + } +} + +void BookmarkModelListener::BookmarkModelBeingDeleted( + bookmarks::BookmarkModel* model) { + // This is an inconsistent state in the application lifecycle. The bookmark + // model shouldn't disappear. + NOTREACHED(); +} + +void BookmarkModelListener::BookmarkNodeMoved( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* old_parent, + size_t old_index, + const bookmarks::BookmarkNode* new_parent, + size_t new_index) { + if ([observer_ respondsToSelector:@selector(bookmarkNode: + movedFromParent:toParent:)]) { + const bookmarks::BookmarkNode* node = + new_parent->children()[new_index].get(); + + IOSBookmarkNode* ios_node = [[IOSBookmarkNode alloc] initWithNode:node + model:model]; + IOSBookmarkNode* ios_old_parent = [[IOSBookmarkNode alloc] initWithNode:old_parent + model:model]; + IOSBookmarkNode* ios_new_parent = [[IOSBookmarkNode alloc] initWithNode:new_parent + model:model]; + + [observer_ bookmarkNode:ios_node + movedFromParent:ios_old_parent + toParent:ios_new_parent]; + } +} + +void BookmarkModelListener::BookmarkNodeAdded( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + size_t index) { + if ([observer_ respondsToSelector:@selector(bookmarkNodeChildrenChanged:)]) { + IOSBookmarkNode* ios_parent = [[IOSBookmarkNode alloc] initWithNode:parent + model:model]; + [observer_ bookmarkNodeChildrenChanged:ios_parent]; + } +} + +void BookmarkModelListener::BookmarkNodeRemoved( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + size_t old_index, + const bookmarks::BookmarkNode* node, + const std::set& removed_urls) { + IOSBookmarkNode* ios_node = [[IOSBookmarkNode alloc] initWithNode:node model:model]; + IOSBookmarkNode* ios_parent = [[IOSBookmarkNode alloc] initWithNode:parent + model:model]; + + if ([observer_ respondsToSelector:@selector(bookmarkNodeDeleted: + fromFolder:)]) { + [observer_ bookmarkNodeDeleted:ios_node fromFolder:ios_parent]; + } + + if ([observer_ respondsToSelector:@selector(bookmarkNodeChildrenChanged:)]) { + [observer_ bookmarkNodeChildrenChanged:ios_parent]; + } +} + +void BookmarkModelListener::BookmarkNodeChanged( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) { + if ([observer_ respondsToSelector:@selector(bookmarkNodeChanged:)]) { + IOSBookmarkNode* ios_node = [[IOSBookmarkNode alloc] initWithNode:node + model:model]; + [observer_ bookmarkNodeChanged:ios_node]; + } +} + +void BookmarkModelListener::BookmarkNodeFaviconChanged( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) { + if ([observer_ respondsToSelector:@selector(bookmarkNodeFaviconChanged:)]) { + IOSBookmarkNode* ios_node = [[IOSBookmarkNode alloc] initWithNode:node + model:model]; + [observer_ bookmarkNodeFaviconChanged:ios_node]; + } +} + +void BookmarkModelListener::BookmarkNodeChildrenReordered( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) { + if ([observer_ respondsToSelector:@selector(bookmarkNodeChildrenChanged:)]) { + IOSBookmarkNode* ios_node = [[IOSBookmarkNode alloc] initWithNode:node + model:model]; + [observer_ bookmarkNodeChildrenChanged:ios_node]; + } +} + +void BookmarkModelListener::BookmarkAllUserNodesRemoved( + bookmarks::BookmarkModel* model, + const std::set& removed_urls) { + if ([observer_ respondsToSelector:@selector(bookmarkModelRemovedAllNodes)]) { + [observer_ bookmarkModelRemovedAllNodes]; + } +} +} // namespace ios +} // namespace brave + +@interface BookmarkModelListenerImpl () { + std::unique_ptr observer_; + bookmarks::BookmarkModel* bookmarkModel_; +} +@end + +@implementation BookmarkModelListenerImpl +- (instancetype)init:(id)observer + bookmarkModel:(void*)model { + if ((self = [super init])) { + observer_ = std::make_unique( + observer, static_cast(model)); + bookmarkModel_ = static_cast(model); + } + return self; +} + +- (void)dealloc { + [self destroy]; +} + +- (void)destroy { + observer_.reset(); +} +@end diff --git a/ios/browser/api/bookmarks/exporter/BUILD.gn b/ios/browser/api/bookmarks/exporter/BUILD.gn new file mode 100644 index 000000000000..90422e8e42e4 --- /dev/null +++ b/ios/browser/api/bookmarks/exporter/BUILD.gn @@ -0,0 +1,41 @@ +# 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/. + +import("//build/config/ios/rules.gni") +import("//ios/build/config.gni") + +source_set("exporter") { + configs += [ "//build/config/compiler:enable_arc" ] + + sources = [ + "brave_bookmarks_exporter.h", + "brave_bookmarks_exporter.mm", + "bookmark_html_writer.h", + "bookmark_html_writer.cc", + "bookmarks_encoder.h", + "bookmarks_encoder.cc" + ] + + deps = [ + "//base", + "//components/bookmarks/browser", + "//components/favicon/core", + "//components/favicon_base", + "//components/keyed_service/core:core", + "//components/strings:components_strings_grit", + "//ios/chrome/browser", + "//ios/chrome/browser/bookmarks:bookmarks", + "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/favicon:favicon", + "//ios/web/public/thread", + "//net", + "//ui/base:base", + "//url", + ] + + frameworks = [ + "Foundation.framework", + ] +} diff --git a/ios/browser/api/bookmarks/exporter/bookmark_html_writer.cc b/ios/browser/api/bookmarks/exporter/bookmark_html_writer.cc new file mode 100644 index 000000000000..de714e925436 --- /dev/null +++ b/ios/browser/api/bookmarks/exporter/bookmark_html_writer.cc @@ -0,0 +1,609 @@ +/* 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/ios/browser/api/bookmarks/exporter/bookmark_html_writer.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "base/base64.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/supports_user_data.h" +#include "base/task/post_task.h" +#include "base/task/thread_pool.h" +#include "base/time/time.h" +#include "base/values.h" +#include "components/bookmarks/browser/bookmark_codec.h" +#include "components/bookmarks/browser/bookmark_model.h" +#include "components/favicon/core/favicon_service.h" +#include "components/favicon_base/favicon_types.h" +#include "components/keyed_service/core/service_access_type.h" +#include "components/strings/grit/components_strings.h" +#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#include "ios/chrome/browser/favicon/favicon_service_factory.h" +#include "net/base/escape.h" +#include "ui/base/l10n/l10n_util.h" + +using bookmarks::BookmarkCodec; +using bookmarks::BookmarkNode; + +namespace gfx { +const int kFaviconSize = 16; +} + +namespace { + +const char kBookmarkFaviconFetcherKey[] = "bookmark-favicon-fetcher"; + +// File header. +const char kHeader[] = + "\r\n" + "\r\n" + "\r\n" + "Bookmarks\r\n" + "

Bookmarks

\r\n" + "

\r\n"; + +// Newline separator. +const char kNewline[] = "\r\n"; + +// The following are used for bookmarks. + +// Start of a bookmark. +const char kBookmarkStart[] = "

"; +// End of a bookmark. +const char kBookmarkEnd[] = ""; + +// The following are used when writing folders. + +// Start of a folder. +const char kFolderStart[] = "

"; +// After kLastModified when writing a user created folder. +const char kFolderAttributeEnd[] = "\">"; +// End of the folder. +const char kFolderEnd[] = "

"; +// Start of the children of a folder. +const char kFolderChildren[] = "

"; +// End of the children for a folder. +const char kFolderChildrenEnd[] = "

"; + +// Number of characters to indent by. +const size_t kIndentSize = 4; + +// Fetches favicons for list of bookmarks and then starts Writer which outputs +// bookmarks and favicons to html file. +class BookmarkFaviconFetcher : public base::SupportsUserData::Data { + public: + // Map of URL and corresponding favicons. + typedef std::map> + URLFaviconMap; + + BookmarkFaviconFetcher(ChromeBrowserState* browser_state, + const base::FilePath& path, + BookmarksExportObserver* observer); + ~BookmarkFaviconFetcher() override = default; + + // Executes bookmark export process. + void ExportBookmarks(); + + private: + // Recursively extracts URLs from bookmarks. + void ExtractUrls(const bookmarks::BookmarkNode* node); + + // Executes Writer task that writes bookmarks data to html file. + void ExecuteWriter(); + + // Starts async fetch for the next bookmark favicon. + // Takes single url from bookmark_urls_ and removes it from the list. + // Returns true if there are more favicons to extract. + bool FetchNextFavicon(); + + // Favicon fetch callback. After all favicons are fetched executes + // html output with |background_io_task_runner_|. + void OnFaviconDataAvailable( + const favicon_base::FaviconRawBitmapResult& bitmap_result); + + // The Profile object used for accessing FaviconService, bookmarks model. + ChromeBrowserState* browser_state_; + + // All URLs that are extracted from bookmarks. Used to fetch favicons + // for each of them. After favicon is fetched top url is removed from list. + std::list bookmark_urls_; + + // Tracks favicon tasks. + base::CancelableTaskTracker cancelable_task_tracker_; + + // Map that stores favicon per URL. + std::unique_ptr favicons_map_; + + // Path where html output is stored. + base::FilePath path_; + + BookmarksExportObserver* observer_; + + DISALLOW_COPY_AND_ASSIGN(BookmarkFaviconFetcher); +}; + +// Class responsible for the actual writing. Takes ownership of favicons_map. +class Writer : public base::RefCountedThreadSafe { + public: + Writer(std::unique_ptr bookmarks, + const base::FilePath& path, + BookmarkFaviconFetcher::URLFaviconMap* favicons_map, + BookmarksExportObserver* observer) + : bookmarks_(std::move(bookmarks)), + path_(path), + favicons_map_(favicons_map), + observer_(observer) {} + + // Writing bookmarks and favicons data to file. + void DoWrite() { + if (!OpenFile()) { + NotifyOnFinish(BookmarksExportObserver::Result::kCouldNotCreateFile); + return; + } + + base::Value* roots = nullptr; + if (!Write(kHeader)) { + NotifyOnFinish(BookmarksExportObserver::Result::kCouldNotWriteHeader); + return; + } + + if (bookmarks_->type() != base::Value::Type::DICTIONARY || + !static_cast(bookmarks_.get()) + ->Get(BookmarkCodec::kRootsKey, &roots) || + roots->type() != base::Value::Type::DICTIONARY) { + NOTREACHED(); // Invalid type for roots key. + } + + base::DictionaryValue* roots_d_value = + static_cast(roots); + base::Value* root_folder_value; + base::Value* other_folder_value = nullptr; + base::Value* mobile_folder_value = nullptr; + if (!roots_d_value->Get(BookmarkCodec::kRootFolderNameKey, + &root_folder_value) || + root_folder_value->type() != base::Value::Type::DICTIONARY || + !roots_d_value->Get(BookmarkCodec::kOtherBookmarkFolderNameKey, + &other_folder_value) || + other_folder_value->type() != base::Value::Type::DICTIONARY || + !roots_d_value->Get(BookmarkCodec::kMobileBookmarkFolderNameKey, + &mobile_folder_value) || + mobile_folder_value->type() != base::Value::Type::DICTIONARY) { + NOTREACHED(); // Invalid type for root folder and/or other folder. + } + + IncrementIndent(); + + if (!WriteNode(*static_cast(root_folder_value), + BookmarkNode::BOOKMARK_BAR) || + !WriteNode(*static_cast(other_folder_value), + BookmarkNode::OTHER_NODE) || + !WriteNode(*static_cast(mobile_folder_value), + BookmarkNode::MOBILE)) { + NotifyOnFinish(BookmarksExportObserver::Result::kCouldNotWriteNodes); + return; + } + + DecrementIndent(); + + Write(kFolderChildrenEnd); + Write(kNewline); + // File close is forced so that unit test could read it. + file_.reset(); + + NotifyOnFinish(BookmarksExportObserver::Result::kSuccess); + } + + private: + friend class base::RefCountedThreadSafe; + + // Types of text being written out. The type dictates how the text is + // escaped. + enum TextType { + // The text is the value of an html attribute, eg foo in + // . + ATTRIBUTE_VALUE, + + // Actual content, eg foo in

foo

. + CONTENT + }; + + ~Writer() {} + + // Opens the file, returning true on success. + bool OpenFile() { + int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE; + file_.reset(new base::File(path_, flags)); + if (!file_->IsValid()) { + PLOG(ERROR) << "Could not create " << path_; + return false; + } + return true; + } + + // Increments the indent. + void IncrementIndent() { indent_.resize(indent_.size() + kIndentSize, ' '); } + + // Decrements the indent. + void DecrementIndent() { + DCHECK(!indent_.empty()); + indent_.resize(indent_.size() - kIndentSize, ' '); + } + + // Called at the end of the export process. + void NotifyOnFinish(BookmarksExportObserver::Result result) { + if (observer_ != nullptr) { + observer_->OnExportFinished(result); + } + } + + // Writes raw text out returning true on success. This does not escape + // the text in anyway. + bool Write(const std::string& text) { + if (!text.length()) + return true; + size_t wrote = file_->WriteAtCurrentPos(text.c_str(), text.length()); + bool result = (wrote == text.length()); + if (!result) { + PLOG(ERROR) << "Could not write text to " << path_; + return false; + } + return true; + } + + // Writes out the text string (as UTF8). The text is escaped based on + // type. + bool Write(const std::string& text, TextType type) { + DCHECK(base::IsStringUTF8(text)); + std::string utf8_string; + + switch (type) { + case ATTRIBUTE_VALUE: + // Convert " to " + utf8_string = text; + base::ReplaceSubstringsAfterOffset(&utf8_string, 0, "\"", """); + break; + + case CONTENT: + utf8_string = net::EscapeForHTML(text); + break; + + default: + NOTREACHED(); + } + + return Write(utf8_string); + } + + // Indents the current line. + bool WriteIndent() { return Write(indent_); } + + // Converts a time string written to the JSON codec into a time_t string + // (used by bookmarks.html) and writes it. + bool WriteTime(const std::string& time_string) { + int64_t internal_value; + base::StringToInt64(time_string, &internal_value); + return Write(base::NumberToString( + base::Time::FromInternalValue(internal_value).ToTimeT())); + } + + // Writes the node and all its children, returning true on success. + bool WriteNode(const base::DictionaryValue& value, + BookmarkNode::Type folder_type) { + std::string title, date_added_string, type_string; + if (!value.GetString(BookmarkCodec::kNameKey, &title) || + !value.GetString(BookmarkCodec::kDateAddedKey, &date_added_string) || + !value.GetString(BookmarkCodec::kTypeKey, &type_string) || + (type_string != BookmarkCodec::kTypeURL && + type_string != BookmarkCodec::kTypeFolder)) { + NOTREACHED(); + return false; + } + + if (type_string == BookmarkCodec::kTypeURL) { + std::string url_string; + if (!value.GetString(BookmarkCodec::kURLKey, &url_string)) { + NOTREACHED(); + return false; + } + + std::string favicon_string; + auto itr = favicons_map_->find(url_string); + if (itr != favicons_map_->end()) { + scoped_refptr data(itr->second.get()); + std::string favicon_base64_encoded; + base::Base64Encode( + base::StringPiece(data->front_as(), data->size()), + &favicon_base64_encoded); + GURL favicon_url("data:image/png;base64," + favicon_base64_encoded); + favicon_string = favicon_url.spec(); + } + + if (!WriteIndent() || !Write(kBookmarkStart) || + !Write(url_string, ATTRIBUTE_VALUE) || !Write(kAddDate) || + !WriteTime(date_added_string) || + (!favicon_string.empty() && + (!Write(kIcon) || !Write(favicon_string, ATTRIBUTE_VALUE))) || + !Write(kBookmarkAttributeEnd) || !Write(title, CONTENT) || + !Write(kBookmarkEnd) || !Write(kNewline)) { + return false; + } + return true; + } + + // Folder. + std::string last_modified_date; + const base::Value* child_values = nullptr; + if (!value.GetString(BookmarkCodec::kDateModifiedKey, + &last_modified_date) || + !value.Get(BookmarkCodec::kChildrenKey, &child_values) || + child_values->type() != base::Value::Type::LIST) { + NOTREACHED(); + return false; + } + if (folder_type != BookmarkNode::OTHER_NODE && + folder_type != BookmarkNode::MOBILE) { + // The other/mobile folder name are not written out. This gives the effect + // of making the contents of the 'other folder' be a sibling to the + // bookmark bar folder. + if (!WriteIndent() || !Write(kFolderStart) || + !WriteTime(date_added_string) || !Write(kLastModified) || + !WriteTime(last_modified_date)) { + return false; + } + if (folder_type == BookmarkNode::BOOKMARK_BAR) { + if (!Write(kBookmarkBar)) + return false; + title = l10n_util::GetStringUTF8(IDS_BOOKMARK_BAR_FOLDER_NAME); + } else if (!Write(kFolderAttributeEnd)) { + return false; + } + if (!Write(title, CONTENT) || !Write(kFolderEnd) || !Write(kNewline) || + !WriteIndent() || !Write(kFolderChildren) || !Write(kNewline)) { + return false; + } + IncrementIndent(); + } + + // Write the children. + const base::ListValue* children = + static_cast(child_values); + for (size_t i = 0; i < children->GetSize(); ++i) { + const base::Value* child_value; + if (!children->Get(i, &child_value) || + child_value->type() != base::Value::Type::DICTIONARY) { + NOTREACHED(); + return false; + } + if (!WriteNode(*static_cast(child_value), + BookmarkNode::FOLDER)) { + return false; + } + } + if (folder_type != BookmarkNode::OTHER_NODE && + folder_type != BookmarkNode::MOBILE) { + // Close out the folder. + DecrementIndent(); + if (!WriteIndent() || !Write(kFolderChildrenEnd) || !Write(kNewline)) { + return false; + } + } + return true; + } + + // The BookmarkModel as a base::Value. This value was generated from the + // BookmarkCodec. + std::unique_ptr bookmarks_; + + // Path we're writing to. + base::FilePath path_; + + // Map that stores favicon per URL. + std::unique_ptr favicons_map_; + + // Observer to be notified on finish. + BookmarksExportObserver* observer_; + + // File we're writing to. + std::unique_ptr file_; + + // How much we indent when writing a bookmark/folder. This is modified + // via IncrementIndent and DecrementIndent. + std::string indent_; + + DISALLOW_COPY_AND_ASSIGN(Writer); +}; + +// A class that allows to export a set of bookmarks encoded as a `base::Value` +class BookmarkWriter { + public: + BookmarkWriter(std::unique_ptr bookmarks, + const base::FilePath& path, + BookmarksExportObserver* observer); + + void ExportBookmarks(); + + private: + void ExecuteWriter(); + + std::unique_ptr bookmarks_; + base::FilePath path_; + BookmarksExportObserver* observer_; + std::unique_ptr favicons_map_; +}; + +} // namespace + +BookmarkFaviconFetcher::BookmarkFaviconFetcher( + ChromeBrowserState* browser_state, + const base::FilePath& path, + BookmarksExportObserver* observer) + : browser_state_(browser_state), path_(path), observer_(observer) { + DCHECK(!browser_state->IsOffTheRecord()); + favicons_map_.reset(new URLFaviconMap()); +} + +void BookmarkFaviconFetcher::ExportBookmarks() { + ExtractUrls(ios::BookmarkModelFactory::GetForBrowserState(browser_state_) + ->bookmark_bar_node()); + ExtractUrls(ios::BookmarkModelFactory::GetForBrowserState(browser_state_) + ->other_node()); + ExtractUrls(ios::BookmarkModelFactory::GetForBrowserState(browser_state_) + ->mobile_node()); + if (!bookmark_urls_.empty()) + FetchNextFavicon(); + else + ExecuteWriter(); +} + +void BookmarkFaviconFetcher::ExtractUrls(const BookmarkNode* node) { + if (node->is_url()) { + std::string url = node->url().spec(); + if (!url.empty()) + bookmark_urls_.push_back(url); + } else { + for (const auto& child : node->children()) + ExtractUrls(child.get()); + } +} + +void BookmarkFaviconFetcher::ExecuteWriter() { + // BookmarkModel isn't thread safe (nor would we want to lock it down + // for the duration of the write), as such we make a copy of the + // BookmarkModel using BookmarkCodec then write from that. + BookmarkCodec codec; + base::ThreadPool::PostTask( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce( + &Writer::DoWrite, + base::MakeRefCounted( + codec.Encode( + ios::BookmarkModelFactory::GetForBrowserState(browser_state_), + /*sync_metadata_str=*/std::string()), + path_, favicons_map_.release(), observer_))); + browser_state_->RemoveUserData(kBookmarkFaviconFetcherKey); + // |this| is deleted! +} + +bool BookmarkFaviconFetcher::FetchNextFavicon() { + if (bookmark_urls_.empty()) { + return false; + } + do { + std::string url = bookmark_urls_.front(); + // Filter out urls that we've already got favicon for. + URLFaviconMap::const_iterator iter = favicons_map_->find(url); + if (favicons_map_->end() == iter) { + favicon::FaviconService* favicon_service = + ios::FaviconServiceFactory::GetForBrowserState( + browser_state_, ServiceAccessType::EXPLICIT_ACCESS); + favicon_service->GetRawFaviconForPageURL( + GURL(url), {favicon_base::IconType::kFavicon}, gfx::kFaviconSize, + /*fallback_to_host=*/false, + base::BindOnce(&BookmarkFaviconFetcher::OnFaviconDataAvailable, + base::Unretained(this)), + &cancelable_task_tracker_); + return true; + } else { + bookmark_urls_.pop_front(); + } + } while (!bookmark_urls_.empty()); + return false; +} + +void BookmarkFaviconFetcher::OnFaviconDataAvailable( + const favicon_base::FaviconRawBitmapResult& bitmap_result) { + GURL url; + if (!bookmark_urls_.empty()) { + url = GURL(bookmark_urls_.front()); + bookmark_urls_.pop_front(); + } + if (bitmap_result.is_valid() && !url.is_empty()) { + favicons_map_->insert(make_pair(url.spec(), bitmap_result.bitmap_data)); + } + + if (FetchNextFavicon()) { + return; + } + ExecuteWriter(); +} + +BookmarkWriter::BookmarkWriter(std::unique_ptr bookmarks, + const base::FilePath& path, + BookmarksExportObserver* observer) + : bookmarks_(std::move(bookmarks)), path_(path), observer_(observer) { + favicons_map_.reset(new BookmarkFaviconFetcher::URLFaviconMap()); +} + +void BookmarkWriter::ExportBookmarks() { + ExecuteWriter(); +} + +void BookmarkWriter::ExecuteWriter() { + base::ThreadPool::PostTask( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce( + &Writer::DoWrite, + base::MakeRefCounted(std::move(bookmarks_), path_, + favicons_map_.release(), observer_))); + delete this; +} + +namespace bookmark_html_writer { + +void WriteBookmarks(ChromeBrowserState* browser_state, + const base::FilePath& path, + BookmarksExportObserver* observer) { + // We allow only one concurrent bookmark export operation per profile. + if (browser_state->GetUserData(kBookmarkFaviconFetcherKey)) + return; + + auto fetcher = + std::make_unique(browser_state, path, observer); + auto* fetcher_ptr = fetcher.get(); + browser_state->SetUserData(kBookmarkFaviconFetcherKey, std::move(fetcher)); + fetcher_ptr->ExportBookmarks(); +} + +void WriteBookmarks(std::unique_ptr encoded_bookmarks, + const base::FilePath& path, + BookmarksExportObserver* observer) { + // Deleted in |ios::BookmarkWriter::ExecuteWriter| + BookmarkWriter* fetcher = + new BookmarkWriter(std::move(encoded_bookmarks), path, observer); + fetcher->ExportBookmarks(); +} + +} // namespace bookmark_html_writer diff --git a/ios/browser/api/bookmarks/exporter/bookmark_html_writer.h b/ios/browser/api/bookmarks/exporter/bookmark_html_writer.h new file mode 100644 index 000000000000..d365a2443a6c --- /dev/null +++ b/ios/browser/api/bookmarks/exporter/bookmark_html_writer.h @@ -0,0 +1,50 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_EXPORTER_BOOKMARK_HTML_WRITER_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_EXPORTER_BOOKMARK_HTML_WRITER_H_ + +#include + +class ChromeBrowserState; + +namespace base { +class FilePath; +class Value; +} // namespace base + +// Observer for bookmark html output. Used only in tests. +class BookmarksExportObserver { + public: + enum class Result { + kSuccess, + kCouldNotCreateFile, + kCouldNotWriteHeader, + kCouldNotWriteNodes, + }; + // Is invoked on the IO thread. + virtual void OnExportFinished(Result result) = 0; + + protected: + virtual ~BookmarksExportObserver() {} +}; + +namespace bookmark_html_writer { + +// Writes the bookmarks out in the 'bookmarks.html' format understood by +// Firefox and IE. The results are written asynchronously to the file at |path|. +// Before writing to the file favicons are fetched on the main thread. +// TODO(sky): need a callback on failure. +void WriteBookmarks(ChromeBrowserState* browser_state, + const base::FilePath& path, + BookmarksExportObserver* observer); + +void WriteBookmarks(std::unique_ptr, + const base::FilePath& path, + BookmarksExportObserver* observer); + +} // namespace bookmark_html_writer + +#endif // BRAVE_IOS_BROWSER_API_BOOKMARKS_EXPORTER_BOOKMARK_HTML_WRITER_H_ diff --git a/ios/browser/api/bookmarks/exporter/bookmarks_encoder.cc b/ios/browser/api/bookmarks/exporter/bookmarks_encoder.cc new file mode 100644 index 000000000000..3c533852d7db --- /dev/null +++ b/ios/browser/api/bookmarks/exporter/bookmarks_encoder.cc @@ -0,0 +1,29 @@ +/* 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/ios/browser/api/bookmarks/exporter/bookmarks_encoder.h" + +#include +#include +#include + +#include "base/values.h" +#include "components/bookmarks/browser/bookmark_codec.h" +#include "components/bookmarks/browser/bookmark_node.h" + +namespace ios { +namespace bookmarks_encoder { +std::unique_ptr Encode( + const bookmarks::BookmarkNode* bookmark_bar_node, + const bookmarks::BookmarkNode* other_folder_node, + const bookmarks::BookmarkNode* mobile_folder_node) { + auto encoder = std::make_unique(); + return encoder->Encode(bookmark_bar_node, other_folder_node, + mobile_folder_node, + /*model_meta_info_map*/ nullptr, + /*sync_metadata_str*/ std::string()); +} +} // namespace bookmarks_encoder +} // namespace ios diff --git a/ios/browser/api/bookmarks/exporter/bookmarks_encoder.h b/ios/browser/api/bookmarks/exporter/bookmarks_encoder.h new file mode 100644 index 000000000000..fdc913491f59 --- /dev/null +++ b/ios/browser/api/bookmarks/exporter/bookmarks_encoder.h @@ -0,0 +1,29 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_EXPORTER_BOOKMARKS_ENCODER_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_EXPORTER_BOOKMARKS_ENCODER_H_ + +#include +#include + +namespace bookmarks { +class BookmarkNode; +} // namespace bookmarks + +namespace base { +class Value; +} // namespace base + +namespace ios { +namespace bookmarks_encoder { +std::unique_ptr Encode( + const bookmarks::BookmarkNode* bookmark_bar_node, + const bookmarks::BookmarkNode* other_folder_node, + const bookmarks::BookmarkNode* mobile_folder_node); +} // namespace bookmarks_encoder +} // namespace ios + +#endif // BRAVE_IOS_BROWSER_API_BOOKMARKS_EXPORTER_BOOKMARKS_ENCODER_H_ diff --git a/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.h b/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.h new file mode 100644 index 000000000000..8ce414f11bcc --- /dev/null +++ b/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.h @@ -0,0 +1,38 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_EXPORTER_BRAVE_BOOKMARKS_EXPORTER_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_EXPORTER_BRAVE_BOOKMARKS_EXPORTER_H_ + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, BraveBookmarksExporterState) { + BraveBookmarksExporterStateCompleted, + BraveBookmarksExporterStateStarted, + BraveBookmarksExporterStateCancelled, + BraveBookmarksExporterStateErrorCreatingFile, + BraveBookmarksExporterStateErrorWritingHeader, + BraveBookmarksExporterStateErrorWritingNodes +}; + +@class IOSBookmarkNode; + +OBJC_EXPORT +@interface BraveBookmarksExporter : NSObject +- (instancetype)init; + +- (void)exportToFile:(NSString*)filePath + withListener:(void (^)(BraveBookmarksExporterState))listener; + +- (void)exportToFile:(NSString*)filePath + bookmarks:(NSArray*)bookmarks + withListener:(void (^)(BraveBookmarksExporterState))listener; +@end + +NS_ASSUME_NONNULL_END + +#endif // BRAVE_IOS_BROWSER_API_BOOKMARKS_EXPORTER_BRAVE_BOOKMARKS_EXPORTER_H_ diff --git a/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.mm b/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.mm new file mode 100644 index 000000000000..e7de4a4a2e21 --- /dev/null +++ b/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.mm @@ -0,0 +1,207 @@ +/* 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/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.h" +#include "brave/ios/browser/api/bookmarks/brave_bookmarks_api.h" + +#include +#include + +#include "base/base_paths.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/compiler_specific.h" +#include "base/files/file_path.h" +#include "base/mac/foundation_util.h" +#include "base/path_service.h" +#include "base/sequenced_task_runner.h" +#include "base/strings/sys_string_conversions.h" +#include "base/task/post_task.h" +#include "base/task/thread_pool.h" +#include "base/values.h" +#include "brave/ios/browser/api/bookmarks/exporter/bookmark_html_writer.h" +#include "brave/ios/browser/api/bookmarks/exporter/bookmarks_encoder.h" +#include "components/bookmarks/browser/bookmark_node.h" +#include "components/strings/grit/components_strings.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#include "ios/web/public/thread/web_task_traits.h" +#include "ios/web/public/thread/web_thread.h" +#import "net/base/mac/url_conversions.h" +#include "ui/base/l10n/l10n_util.h" +#include "url/gurl.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +class BraveBookmarksExportObserver : public BookmarksExportObserver { + public: + BraveBookmarksExportObserver( + std::function on_export_finished); + void OnExportFinished(Result result) override; + + private: + std::function _on_export_finished; +}; + +BraveBookmarksExportObserver::BraveBookmarksExportObserver( + std::function on_export_finished) + : _on_export_finished(on_export_finished) {} + +void BraveBookmarksExportObserver::OnExportFinished(Result result) { + switch (result) { + case Result::kSuccess: + return _on_export_finished(BraveBookmarksExporterStateCompleted); + case Result::kCouldNotCreateFile: + return _on_export_finished(BraveBookmarksExporterStateErrorCreatingFile); + case Result::kCouldNotWriteHeader: + return _on_export_finished(BraveBookmarksExporterStateErrorWritingHeader); + case Result::kCouldNotWriteNodes: + return _on_export_finished(BraveBookmarksExporterStateErrorWritingNodes); + default: + NOTREACHED(); + } + delete this; +} + +@interface IOSBookmarkNode(BookmarksExporter) +- (void)setNativeParent:(bookmarks::BookmarkNode*)parent; +@end + +@interface BraveBookmarksExporter () +@end + +@implementation BraveBookmarksExporter + +- (instancetype)init { + if ((self = [super init])) { + } + return self; +} + +- (void)exportToFile:(NSString*)filePath + withListener:(void (^)(BraveBookmarksExporterState))listener { + auto start_export = + [](BraveBookmarksExporter* weak_exporter, NSString* filePath, + std::function listener) { + // Export cancelled as the exporter has been deallocated + __strong BraveBookmarksExporter* exporter = weak_exporter; + if (!exporter) { + listener(BraveBookmarksExporterStateStarted); + listener(BraveBookmarksExporterStateCancelled); + return; + } + + DCHECK(GetApplicationContext()); + + base::FilePath destination_file_path = + base::mac::NSStringToFilePath(filePath); + + listener(BraveBookmarksExporterStateStarted); + + ios::ChromeBrowserStateManager* browserStateManager = + GetApplicationContext()->GetChromeBrowserStateManager(); + DCHECK(browserStateManager); + + ChromeBrowserState* chromeBrowserState = + browserStateManager->GetLastUsedBrowserState(); + DCHECK(chromeBrowserState); + + bookmark_html_writer::WriteBookmarks( + chromeBrowserState, destination_file_path, + new BraveBookmarksExportObserver(listener)); + }; + + __weak BraveBookmarksExporter* weakSelf = self; + base::PostTask(FROM_HERE, {web::WebThread::UI}, + base::BindOnce(start_export, weakSelf, filePath, listener)); +} + +- (void)exportToFile:(NSString*)filePath + bookmarks:(NSArray*)bookmarks + withListener:(void (^)(BraveBookmarksExporterState))listener { + if ([bookmarks count] == 0) { + listener(BraveBookmarksExporterStateStarted); + listener(BraveBookmarksExporterStateCompleted); + return; + } + + auto start_export = + [](BraveBookmarksExporter* weak_exporter, NSString* filePath, + NSArray* bookmarks, + std::function listener) { + // Export cancelled as the exporter has been deallocated + __strong BraveBookmarksExporter* exporter = weak_exporter; + if (!exporter) { + listener(BraveBookmarksExporterStateStarted); + listener(BraveBookmarksExporterStateCancelled); + return; + } + + listener(BraveBookmarksExporterStateStarted); + base::FilePath destination_file_path = + base::mac::NSStringToFilePath(filePath); + + // Create artificial nodes + auto bookmark_bar_node = [exporter getBookmarksBarNode]; + auto other_folder_node = [exporter getOtherBookmarksNode]; + auto mobile_folder_node = [exporter getMobileBookmarksNode]; + + for (IOSBookmarkNode* bookmark : bookmarks) { + // We export as the |mobile_bookmarks_node| by default. + [bookmark setNativeParent:mobile_folder_node.get()]; + } + + auto encoded_bookmarks = + ios::bookmarks_encoder::Encode(bookmark_bar_node.get(), + other_folder_node.get(), + mobile_folder_node.get()); + bookmark_html_writer::WriteBookmarks( + std::move(encoded_bookmarks), destination_file_path, + new BraveBookmarksExportObserver(listener)); + }; + + __weak BraveBookmarksExporter* weakSelf = self; + base::PostTask( + FROM_HERE, + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}, + base::BindOnce(start_export, weakSelf, filePath, bookmarks, listener)); +} + +// MARK: - Internal artificial nodes used for exporting arbitrary bookmarks to a file + +- (std::unique_ptr)getRootNode { + return std::make_unique(/*id=*/0, + bookmarks::BookmarkNode::kRootNodeGuid, + GURL()); +} + +- (std::unique_ptr)getBookmarksBarNode { + auto node = std::make_unique(/*id=*/1, + bookmarks::BookmarkNode::kBookmarkBarNodeGuid, + GURL()); + node->SetTitle(l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_FOLDER_NAME)); + return node; +} + +- (std::unique_ptr)getOtherBookmarksNode { + auto node = std::make_unique(/*id=*/2, + bookmarks::BookmarkNode::kOtherBookmarksNodeGuid, + GURL()); + node->SetTitle(l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME)); + return node; +} + +- (std::unique_ptr)getMobileBookmarksNode { + auto node = std::make_unique(/*id=*/3, + bookmarks::BookmarkNode::kMobileBookmarksNodeGuid, + GURL()); + node->SetTitle(l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME)); + return node; +} +@end diff --git a/ios/browser/api/bookmarks/importer/BUILD.gn b/ios/browser/api/bookmarks/importer/BUILD.gn new file mode 100644 index 000000000000..8ff5fe594a56 --- /dev/null +++ b/ios/browser/api/bookmarks/importer/BUILD.gn @@ -0,0 +1,46 @@ +# 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/. + +import("//build/config/ios/rules.gni") +import("//ios/build/config.gni") + +source_set("importer") { + configs += [ "//build/config/compiler:enable_arc" ] + + sources = [ + "brave_bookmarks_importer.h", + "brave_bookmarks_importer.mm", + "bookmarks_importer.h", + "bookmarks_importer.cc", + "bookmark_html_reader.h", + "bookmark_html_reader.cc", + "imported_bookmark_entry.h", + "imported_bookmark_entry.cc", + "favicon_reencode.h", + "favicon_reencode.mm", + ] + + deps = [ + "//base", + "//components/bookmarks/browser:browser", + "//components/bookmarks/common:common", + "//components/favicon_base", + "//components/prefs:prefs", + "//components/search_engines:search_engines", + "//components/strings:components_strings_grit", + "//components/user_prefs:user_prefs", + "//ios/chrome/browser/bookmarks", + "//ios/chrome/browser/browser_state", + "//ios/chrome/browser:browser", + "//ios/web/public/thread", + "//net", + "//ui/base:base", + "//url", + ] + + frameworks = [ + "Foundation.framework", + ] +} diff --git a/ios/browser/api/bookmarks/importer/bookmark_html_reader.cc b/ios/browser/api/bookmarks/importer/bookmark_html_reader.cc new file mode 100644 index 000000000000..a207d4cfcbf7 --- /dev/null +++ b/ios/browser/api/bookmarks/importer/bookmark_html_reader.cc @@ -0,0 +1,507 @@ +/* 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/ios/browser/api/bookmarks/importer/bookmark_html_reader.h" + +#include +#include + +#include "base/callback.h" +#include "base/files/file_util.h" +#include "base/i18n/icu_string_conversions.h" +#include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "brave/ios/browser/api/bookmarks/importer/imported_bookmark_entry.h" +#include "brave/ios/browser/api/bookmarks/importer/favicon_reencode.h" +#include "components/search_engines/search_terms_data.h" +#include "components/search_engines/template_url.h" +#include "net/base/data_url.h" +#include "net/base/escape.h" +#include "url/gurl.h" +#include "url/url_constants.h" + +namespace { + +// Fetches the given |attribute| value from the |attribute_list|. Returns true +// if successful, and |value| will contain the value. +bool GetAttribute(const std::string& attribute_list, + const std::string& attribute, + std::string* value) { + const char kQuote[] = "\""; + + size_t begin = attribute_list.find(attribute + "=" + kQuote); + if (begin == std::string::npos) + return false; // Can't find the attribute. + + begin += attribute.size() + 2; + size_t end = begin + 1; + + while (end < attribute_list.size()) { + if (attribute_list[end] == '"' && + attribute_list[end - 1] != '\\') { + break; + } + end++; + } + + if (end == attribute_list.size()) + return false; // The value is not quoted. + + *value = attribute_list.substr(begin, end - begin); + return true; +} + +// Given the URL of a page and a favicon data URL, adds an appropriate record +// to the given favicon usage vector. +void DataURLToFaviconUsage(const GURL& link_url, + const GURL& favicon_data, + favicon_base::FaviconUsageDataList* favicons) { + if (!link_url.is_valid() || !favicon_data.is_valid() || + !favicon_data.SchemeIs(url::kDataScheme)) + return; + + // Parse the data URL. + std::string mime_type, char_set, data; + if (!net::DataURL::Parse(favicon_data, &mime_type, &char_set, &data) || + data.empty()) + return; + + favicon_base::FaviconUsageData usage; + if (!importer::ReencodeFavicon( + reinterpret_cast(&data[0]), + data.size(), &usage.png_data)) + return; // Unable to decode. + + // We need to make up a URL for the favicon. We use a version of the page's + // URL so that we can be sure it will not collide. + usage.favicon_url = GURL(std::string("made-up-favicon:") + link_url.spec()); + + // We only have one URL per favicon for Firefox 2 bookmarks. + usage.urls.insert(link_url); + + favicons->push_back(usage); +} + +} // namespace + +namespace bookmark_html_reader { + +static std::string stripDt(const std::string& lineDt) { + // Remove "
" if the line starts with "
". This may not occur if + // "
" was on the previous line. Liberally accept entries that do not + // have an opening "
" at all. + std::string line = lineDt; + static const char kDtTag[] = "
"; + if (base::StartsWith(line, kDtTag, + base::CompareCase::INSENSITIVE_ASCII)) { + line.erase(0, base::size(kDtTag) - 1); + base::TrimString(line, " ", &line); + } + return line; +} + +void ImportBookmarksFile( + base::RepeatingCallback cancellation_callback, + base::RepeatingCallback valid_url_callback, + const base::FilePath& file_path, + std::vector* bookmarks, + favicon_base::FaviconUsageDataList* favicons) { + std::string content; + base::ReadFileToString(file_path, &content); + std::vector lines = base::SplitString( + content, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + + base::string16 last_folder; + bool last_folder_on_toolbar = false; + bool last_folder_is_empty = true; + bool has_subfolder = false; + bool has_last_folder = false; + base::Time last_folder_add_date; + std::vector path; + size_t toolbar_folder_index = 0; + std::string charset = "UTF-8"; // If no charset is specified, assume utf-8. + for (size_t i = 0; + i < lines.size() && + (cancellation_callback.is_null() || !cancellation_callback.Run()); + ++i) { + std::string line; + base::TrimString(lines[i], " ", &line); + + // Remove "
" if |line| starts with it. "
" is the bookmark entries + // separator in Firefox that Chrome does not support. Note that there can be + // multiple "
" tags at the beginning of a single line. + // See http://crbug.com/257474. + static const char kHrTag[] = "
"; + while (base::StartsWith(line, kHrTag, + base::CompareCase::INSENSITIVE_ASCII)) { + line.erase(0, base::size(kHrTag) - 1); + base::TrimString(line, " ", &line); + } + + // Get the encoding of the bookmark file. + if (internal::ParseCharsetFromLine(line, &charset)) + continue; + + // Get the folder name. + if (internal::ParseFolderNameFromLine(line, + charset, + &last_folder, + &last_folder_on_toolbar, + &last_folder_add_date)) { + has_last_folder = true; + continue; + } + + // Get the bookmark entry. + base::string16 title; + base::string16 shortcut; + GURL url, favicon; + base::Time add_date; + base::string16 post_data; + bool is_bookmark; + // TODO(jcampan): http://b/issue?id=1196285 we do not support POST based + // keywords yet. + is_bookmark = + internal::ParseBookmarkFromLine(line, charset, &title, + &url, &favicon, &shortcut, + &add_date, &post_data) || + internal::ParseMinimumBookmarkFromLine(line, charset, &title, &url); + + // If bookmark contains a valid replaceable url and a keyword then import + // it as search engine. + std::string search_engine_url; + if (is_bookmark && post_data.empty() && + CanImportURLAsSearchEngine(url, &search_engine_url) && + !shortcut.empty()) { + continue; // Do not Import search engines on iOS.. - Brandon T. + } + + if (is_bookmark) + last_folder_is_empty = false; + + if (is_bookmark && + post_data.empty() && + (valid_url_callback.is_null() || valid_url_callback.Run(url))) { + if (toolbar_folder_index > path.size() && !path.empty()) { + NOTREACHED(); // error in parsing. + break; + } + + ImportedBookmarkEntry entry; + entry.creation_time = add_date; + entry.url = url; + entry.title = title; + + if (toolbar_folder_index) { + // The toolbar folder should be at the top level. + entry.in_toolbar = true; + entry.path.assign(path.begin() + toolbar_folder_index - 1, path.end()); + } else { + // Add this bookmark to the list of |bookmarks|. + if (!has_subfolder && has_last_folder) { + path.push_back(last_folder); + has_last_folder = false; + last_folder.clear(); + } + entry.path.assign(path.begin(), path.end()); + } + bookmarks->push_back(entry); + + // Save the favicon. DataURLToFaviconUsage will handle the case where + // there is no favicon. + if (favicons) + DataURLToFaviconUsage(url, favicon, favicons); + + continue; + } + + // Bookmarks in sub-folder are encapsulated with
tag. + if (base::StartsWith(line, "
", base::CompareCase::INSENSITIVE_ASCII)) { + has_subfolder = true; + if (has_last_folder) { + path.push_back(last_folder); + has_last_folder = false; + last_folder.clear(); + } + if (last_folder_on_toolbar && !toolbar_folder_index) + toolbar_folder_index = path.size(); + + // Mark next folder empty as initial state. + last_folder_is_empty = true; + } else if (base::StartsWith(line, "
", + base::CompareCase::INSENSITIVE_ASCII)) { + if (path.empty()) + break; // Mismatch
. + + base::string16 folder_title = path.back(); + path.pop_back(); + + if (last_folder_is_empty) { + // Empty folder should be added explicitly. + ImportedBookmarkEntry entry; + entry.is_folder = true; + entry.creation_time = last_folder_add_date; + entry.title = folder_title; + if (toolbar_folder_index) { + // The toolbar folder should be at the top level. + // Make sure we don't add the toolbar folder itself if it is empty. + if (toolbar_folder_index <= path.size()) { + entry.in_toolbar = true; + entry.path.assign(path.begin() + toolbar_folder_index - 1, + path.end()); + bookmarks->push_back(entry); + } + } else { + // Add this folder to the list of |bookmarks|. + entry.path.assign(path.begin(), path.end()); + bookmarks->push_back(entry); + } + + // Parent folder include current one, so it's not empty. + last_folder_is_empty = false; + } + + if (toolbar_folder_index > path.size()) + toolbar_folder_index = 0; + } + } +} + +bool CanImportURLAsSearchEngine(const GURL& url, + std::string* search_engine_url) { + std::string url_spec = url.possibly_invalid_spec(); + + if (url_spec.empty()) + return false; + + // Any occurrences of "%s" in the original URL string will have been escaped + // as "%25s" by the GURL constructor. Restore them back to "%s". + // Note: It is impossible to distinguish a literal "%25s" in the source string + // from "%s". If the source string does contain "%25s", it will unfortunately + // be converted to "%s" and erroneously used as a template. See + // https://crbug.com/868214. + base::ReplaceSubstringsAfterOffset(&url_spec, 0, "%25s", "%s"); + + // Replace replacement terms ("%s") in |url_spec| with {searchTerms}. + url_spec = + TemplateURLRef::DisplayURLToURLRef(base::UTF8ToUTF16(url_spec)); + + TemplateURLData data; + data.SetURL(url_spec); + *search_engine_url = url_spec; + return TemplateURL(data).SupportsReplacement(SearchTermsData()); +} + +namespace internal { + +bool ParseCharsetFromLine(const std::string& line, std::string* charset) { + if (!base::StartsWith(line, "', end) + 1; + // If no end tag or start tag is broken, we skip to find the folder name. + if (end == std::string::npos || tag_end < base::size(kFolderOpen)) + return false; + + base::CodepageToUTF16(line.substr(tag_end, end - tag_end), charset.c_str(), + base::OnStringConversionError::SKIP, folder_name); + *folder_name = net::UnescapeForHTML(*folder_name); + + std::string attribute_list = line.substr( + base::size(kFolderOpen), tag_end - base::size(kFolderOpen) - 1); + std::string value; + + // Add date + if (GetAttribute(attribute_list, kAddDateAttribute, &value)) { + int64_t time; + base::StringToInt64(value, &time); + // Upper bound it at 32 bits. + if (0 < time && time < (1LL << 32)) + *add_date = base::Time::FromTimeT(time); + } + + if (GetAttribute(attribute_list, kToolbarFolderAttribute, &value) && + base::LowerCaseEqualsASCII(value, "true")) + *is_toolbar_folder = true; + else + *is_toolbar_folder = false; + + return true; +} + +bool ParseBookmarkFromLine(const std::string& lineDt, + const std::string& charset, + base::string16* title, + GURL* url, + GURL* favicon, + base::string16* shortcut, + base::Time* add_date, + base::string16* post_data) { + const char kItemOpen[] = "clear(); + *url = GURL(); + *favicon = GURL(); + shortcut->clear(); + post_data->clear(); + *add_date = base::Time(); + + if (!base::StartsWith(line, kItemOpen, base::CompareCase::SENSITIVE)) + return false; + + size_t end = line.find(kItemClose); + size_t tag_end = line.rfind('>', end) + 1; + if (end == std::string::npos || tag_end < base::size(kItemOpen)) + return false; // No end tag or start tag is broken. + + std::string attribute_list = + line.substr(base::size(kItemOpen), tag_end - base::size(kItemOpen) - 1); + + // We don't import Live Bookmark folders, which is Firefox's RSS reading + // feature, since the user never necessarily bookmarked them and we don't + // have this feature to update their contents. + std::string value; + if (GetAttribute(attribute_list, kFeedURLAttribute, &value)) + return false; + + // Title + base::CodepageToUTF16(line.substr(tag_end, end - tag_end), charset.c_str(), + base::OnStringConversionError::SKIP, title); + *title = net::UnescapeForHTML(*title); + + // URL + if (GetAttribute(attribute_list, kHrefAttribute, &value)) { + base::string16 url16; + base::CodepageToUTF16(value, charset.c_str(), + base::OnStringConversionError::SKIP, &url16); + url16 = net::UnescapeForHTML(url16); + + *url = GURL(url16); + } + + // Favicon + if (GetAttribute(attribute_list, kIconAttribute, &value)) + *favicon = GURL(value); + + // Keyword + if (GetAttribute(attribute_list, kShortcutURLAttribute, &value)) { + base::CodepageToUTF16(value, charset.c_str(), + base::OnStringConversionError::SKIP, shortcut); + *shortcut = net::UnescapeForHTML(*shortcut); + } + + // Add date + if (GetAttribute(attribute_list, kAddDateAttribute, &value)) { + int64_t time; + base::StringToInt64(value, &time); + // Upper bound it at 32 bits. + if (0 < time && time < (1LL << 32)) + *add_date = base::Time::FromTimeT(time); + } + + // Post data. + if (GetAttribute(attribute_list, kPostDataAttribute, &value)) { + base::CodepageToUTF16(value, charset.c_str(), + base::OnStringConversionError::SKIP, post_data); + *post_data = net::UnescapeForHTML(*post_data); + } + + return true; +} + +bool ParseMinimumBookmarkFromLine(const std::string& lineDt, + const std::string& charset, + base::string16* title, + GURL* url) { + const char kItemOpen[] = "clear(); + *url = GURL(); + + // Case-insensitive check of open tag. + if (!base::StartsWith(line, kItemOpen, base::CompareCase::INSENSITIVE_ASCII)) + return false; + + // Find any close tag. + size_t end = line.find(kItemClose); + size_t tag_end = line.rfind('>', end) + 1; + if (end == std::string::npos || tag_end < base::size(kItemOpen)) + return false; // No end tag or start tag is broken. + + std::string attribute_list = + line.substr(base::size(kItemOpen), tag_end - base::size(kItemOpen) - 1); + + // Title + base::CodepageToUTF16(line.substr(tag_end, end - tag_end), charset.c_str(), + base::OnStringConversionError::SKIP, title); + *title = net::UnescapeForHTML(*title); + + // URL + std::string value; + if (GetAttribute(attribute_list, kHrefAttributeUpper, &value) || + GetAttribute(attribute_list, kHrefAttributeLower, &value)) { + if (charset.length() != 0) { + base::string16 url16; + base::CodepageToUTF16(value, charset.c_str(), + base::OnStringConversionError::SKIP, &url16); + url16 = net::UnescapeForHTML(url16); + + *url = GURL(url16); + } else { + *url = GURL(value); + } + } + + return true; +} + +} // namespace internal + +} // namespace bookmark_html_reader diff --git a/ios/browser/api/bookmarks/importer/bookmark_html_reader.h b/ios/browser/api/bookmarks/importer/bookmark_html_reader.h new file mode 100644 index 000000000000..7c4027474499 --- /dev/null +++ b/ios/browser/api/bookmarks/importer/bookmark_html_reader.h @@ -0,0 +1,107 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_BOOKMARK_HTML_READER_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_BOOKMARK_HTML_READER_H_ + +#include +#include + +#include "base/callback_forward.h" +#include "base/strings/string16.h" +#include "components/favicon_base/favicon_usage_data.h" + +class GURL; +struct ImportedBookmarkEntry; + +namespace base { +class FilePath; +class Time; +} + +namespace bookmark_html_reader { + +// Imports the bookmarks from the specified file. +// +// |cancellation_callback| is polled to query if the import should be cancelled; +// if it returns |true| at any time the import will be cancelled. If +// |cancellation_callback| is a null callback the import will run to completion. +// +// |valid_url_callback| is called to determine if a specified URL is valid for +// import; it returns |true| if it is. If |valid_url_callback| is a null +// callback, all URLs are considered to be valid. +// +// |file_path| is the path of the file on disk to import. +// +// |bookmarks| is a pointer to a vector, which is filled with the imported +// bookmarks. It may not be NULL. +// +// |search_engines| is a pointer to a vector, which is filled with the imported +// search engines. +// +// |favicons| is a pointer to a vector, which is filled with the favicons of +// imported bookmarks. It may be NULL, in which case favicons are not imported. +void ImportBookmarksFile( + base::RepeatingCallback cancellation_callback, + base::RepeatingCallback valid_url_callback, + const base::FilePath& file_path, + std::vector* bookmarks, + favicon_base::FaviconUsageDataList* favicons); + +// Returns true if |url| should be imported as a search engine, i.e. because it +// has replacement terms. Chrome treats such bookmarks as search engines rather +// than true bookmarks. +bool CanImportURLAsSearchEngine(const GURL& url, + std::string* search_engine_url); + +namespace internal { + +// The file format that BookmarkHTMLReader parses starts with a heading +// tag, which contains its title. All bookmarks and sub-folders follow, +// bracketed by a
tag: +//

title

+//

+// ... container ... +//

+// And a bookmark is presented by a tag: +//

name +// Reference: http://kb.mozillazine.org/Bookmarks.html + +bool ParseCharsetFromLine(const std::string& line, + std::string* charset); +bool ParseFolderNameFromLine(const std::string& line, + const std::string& charset, + base::string16* folder_name, + bool* is_toolbar_folder, + base::Time* add_date); +// See above, this will also put the data: URL of the favicon into |*favicon| +// if there is a favicon given. |post_data| is set for POST base keywords to +// the contents of the actual POST (with %s for the search term). +bool ParseBookmarkFromLine(const std::string& line, + const std::string& charset, + base::string16* title, + GURL* url, + GURL* favicon, + base::string16* shortcut, + base::Time* add_date, + base::string16* post_data); +// Save bookmarks imported from browsers with Firefox 2 compatible bookmark +// systems such as Epiphany. This bookmark format is the same as that of the +// basic Firefox 2 bookmark, but it misses additional properties and uses +// lower-case tag: +// ...

Bookmarks

+//
name
+//
name
+//
+bool ParseMinimumBookmarkFromLine(const std::string& line, + const std::string& charset, + base::string16* title, + GURL* url); + +} // namespace internal + +} // namespace bookmark_html_reader + +#endif // BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_BOOKMARK_HTML_READER_H_ diff --git a/ios/browser/api/bookmarks/importer/bookmarks_importer.cc b/ios/browser/api/bookmarks/importer/bookmarks_importer.cc new file mode 100644 index 000000000000..ca390e2e7d6e --- /dev/null +++ b/ios/browser/api/bookmarks/importer/bookmarks_importer.cc @@ -0,0 +1,182 @@ +/* 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/ios/browser/api/bookmarks/importer/bookmarks_importer.h" + +#include + +#include "base/base_paths.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "brave/ios/browser/api/bookmarks/importer/imported_bookmark_entry.h" +#include "components/bookmarks/browser/bookmark_model.h" +#include "components/bookmarks/browser/bookmark_node.h" +#include "components/bookmarks/browser/bookmark_utils.h" +#include "components/bookmarks/common/bookmark_pref_names.h" +#include "components/prefs/pref_service.h" +#include "components/strings/grit/components_strings.h" +#include "components/user_prefs/user_prefs.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#include "ui/base/l10n/l10n_util.h" +#include "url/gurl.h" + +using bookmarks::BookmarkModel; +using bookmarks::BookmarkNode; + +namespace { + +// Generates a unique folder name. If |folder_name| is not unique, then this +// repeatedly tests for '|folder_name| + (i)' until a unique name is found. +base::string16 GenerateUniqueFolderName(BookmarkModel* model, + const base::string16& folder_name) { + // Build a set containing the bookmark bar folder names. + std::set existing_folder_names; + const BookmarkNode* bookmark_bar = model->bookmark_bar_node(); + for (const auto& node : bookmark_bar->children()) { + if (node->is_folder()) + existing_folder_names.insert(node->GetTitle()); + } + + // If the given name is unique, use it. + if (existing_folder_names.find(folder_name) == existing_folder_names.end()) + return folder_name; + + // Otherwise iterate until we find a unique name. + for (size_t i = 1; i <= existing_folder_names.size(); ++i) { + base::string16 name = folder_name + base::ASCIIToUTF16(" (") + + base::NumberToString16(i) + base::ASCIIToUTF16(")"); + if (existing_folder_names.find(name) == existing_folder_names.end()) + return name; + } + + NOTREACHED(); + return folder_name; +} + +// Shows the bookmarks toolbar. +void ShowBookmarkBar(ChromeBrowserState* browser_state) { + browser_state->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, + true); +} + +} // namespace + +void BookmarksImporter::AddBookmarks( + const base::string16& top_level_folder_name, + const std::vector& bookmarks) { + if (bookmarks.empty()) + return; + + ios::ChromeBrowserStateManager* browser_state_manager = + GetApplicationContext()->GetChromeBrowserStateManager(); + ChromeBrowserState* browser_state = + browser_state_manager->GetLastUsedBrowserState(); + BookmarkModel* model = + ios::BookmarkModelFactory::GetForBrowserState(browser_state); + DCHECK(model->loaded()); + + // If the bookmark bar is currently empty, we should import directly to it. + // Otherwise, we should import everything to a subfolder. + // For iOS, import into the Mobile Bookmarks Node - Brandon T. + const BookmarkNode* bookmark_bar = model->mobile_node(); + bool import_to_top_level = bookmark_bar->children().empty(); + + // Reorder bookmarks so that the toolbar entries come first. + std::vector toolbar_bookmarks; + std::vector reordered_bookmarks; + for (auto it = bookmarks.begin(); it != bookmarks.end(); ++it) { + if (it->in_toolbar) + toolbar_bookmarks.push_back(*it); + else + reordered_bookmarks.push_back(*it); + } + reordered_bookmarks.insert(reordered_bookmarks.begin(), + toolbar_bookmarks.begin(), + toolbar_bookmarks.end()); + + // If the user currently has no bookmarks in the bookmark bar, make sure that + // at least some of the imported bookmarks end up there. Otherwise, we'll end + // up with just a single folder containing the imported bookmarks, which makes + // for unnecessary nesting. + bool add_all_to_top_level = import_to_top_level && toolbar_bookmarks.empty(); + + model->BeginExtensiveChanges(); + + std::set folders_added_to; + const BookmarkNode* top_level_folder = NULL; + for (std::vector::const_iterator bookmark = + reordered_bookmarks.begin(); + bookmark != reordered_bookmarks.end(); ++bookmark) { + // Disregard any bookmarks with invalid urls. + if (!bookmark->is_folder && !bookmark->url.is_valid()) + continue; + + const BookmarkNode* parent = NULL; + if (import_to_top_level && (add_all_to_top_level || bookmark->in_toolbar)) { + // Add directly to the bookmarks bar. + parent = bookmark_bar; + } else { + // Add to a folder that will contain all the imported bookmarks not added + // to the bar. The first time we do so, create the folder. + if (!top_level_folder) { + base::string16 name = + GenerateUniqueFolderName(model, top_level_folder_name); + top_level_folder = model->AddFolder( + bookmark_bar, bookmark_bar->children().size(), name); + } + parent = top_level_folder; + } + + // Ensure any enclosing folders are present in the model. The bookmark's + // enclosing folder structure should be + // path[0] > path[1] > ... > path[size() - 1] + for (auto folder_name = bookmark->path.begin(); + folder_name != bookmark->path.end(); ++folder_name) { + if (bookmark->in_toolbar && parent == bookmark_bar && + folder_name == bookmark->path.begin()) { + // If we're importing directly to the bookmarks bar, skip over the + // folder named "Bookmarks Toolbar" (or any non-Firefox equivalent). + continue; + } + + const auto it = std::find_if( + parent->children().cbegin(), parent->children().cend(), + [folder_name](const auto& node) { + return node->is_folder() && node->GetTitle() == *folder_name; + }); + parent = (it == parent->children().cend()) + ? model->AddFolder(parent, parent->children().size(), + *folder_name) + : it->get(); + } + + folders_added_to.insert(parent); + if (bookmark->is_folder) { + model->AddFolder(parent, parent->children().size(), bookmark->title); + } else { + model->AddURL(parent, parent->children().size(), bookmark->title, + bookmark->url, nullptr, bookmark->creation_time); + } + } + + // In order to keep the imported-to folders from appearing in the 'recently + // added to' combobox, reset their modified times. + for (auto i = folders_added_to.begin(); i != folders_added_to.end(); ++i) { + model->ResetDateFolderModified(*i); + } + + model->EndExtensiveChanges(); + + // If the user was previously using a toolbar, we should show the bar. + if (import_to_top_level && !add_all_to_top_level) + ShowBookmarkBar(browser_state); +} diff --git a/ios/browser/api/bookmarks/importer/bookmarks_importer.h b/ios/browser/api/bookmarks/importer/bookmarks_importer.h new file mode 100644 index 000000000000..e88c341bfed8 --- /dev/null +++ b/ios/browser/api/bookmarks/importer/bookmarks_importer.h @@ -0,0 +1,23 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_BOOKMARKS_IMPORTER_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_BOOKMARKS_IMPORTER_H_ + +#include + +#include "base/strings/string16.h" +#include "brave/ios/browser/api/bookmarks/importer/imported_bookmark_entry.h" + +class BookmarksImporter { + public: + // top_level_folder_name is usually set to IDS_BOOKMARK_GROUP + // Which is the name of the folder bookmarks will be imported into, + // if the root folder is not empty. + static void AddBookmarks(const base::string16& top_level_folder_name, + const std::vector& bookmarks); +}; + +#endif // BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_BOOKMARKS_IMPORTER_H_ diff --git a/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.h b/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.h new file mode 100644 index 000000000000..be3a80828e60 --- /dev/null +++ b/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.h @@ -0,0 +1,50 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_BRAVE_BOOKMARKS_IMPORTER_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_BRAVE_BOOKMARKS_IMPORTER_H_ + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, BraveBookmarksImporterState) { + BraveBookmarksImporterStateCompleted, + BraveBookmarksImporterStateAutoCompleted, + BraveBookmarksImporterStateStarted, + BraveBookmarksImporterStateCancelled +}; + +OBJC_EXPORT +@interface BraveImportedBookmark : NSObject +@property(nonatomic, readonly) bool inToolbar; +@property(nonatomic, readonly) bool isFolder; +@property(nullable, nonatomic, readonly, copy) NSURL* url; +@property(nullable, nonatomic, readonly, copy) NSArray* path; +@property(nonatomic, readonly, copy) NSString* title; +@property(nonatomic, readonly, copy) NSDate* creationTime; +@end + +OBJC_EXPORT +@interface BraveBookmarksImporter : NSObject +- (instancetype)init; + +- (void)cancel; + +- (void)importFromFile:(NSString*)filePath + topLevelFolderName:(NSString*)folderName + automaticImport:(bool)automaticImport + withListener: + (void (^)(BraveBookmarksImporterState, + NSArray* _Nullable))listener; + +- (void)importFromArray:(NSArray*)bookmarks + topLevelFolderName:(NSString*)folderName + withListener:(void (^)(BraveBookmarksImporterState))listener; +@end + +NS_ASSUME_NONNULL_END + +#endif // BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_BRAVE_BOOKMARKS_IMPORTER_H_ diff --git a/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.mm b/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.mm new file mode 100644 index 000000000000..e346e65f3060 --- /dev/null +++ b/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.mm @@ -0,0 +1,252 @@ +/* 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/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.h" + +#include + +#include "base/base_paths.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/compiler_specific.h" +#include "base/files/file_path.h" +#include "base/mac/foundation_util.h" +#include "base/path_service.h" +#include "base/sequenced_task_runner.h" +#include "base/strings/sys_string_conversions.h" +#include "base/task/post_task.h" +#include "base/task/thread_pool.h" +#include "brave/ios/browser/api/bookmarks/importer/bookmark_html_reader.h" +#include "brave/ios/browser/api/bookmarks/importer/bookmarks_importer.h" +#include "brave/ios/browser/api/bookmarks/importer/imported_bookmark_entry.h" +#include "ios/web/public/thread/web_task_traits.h" +#include "ios/web/public/thread/web_thread.h" +#import "net/base/mac/url_conversions.h" +#include "url/gurl.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation BraveImportedBookmark +- (instancetype)initFromChromiumImportedBookmark: + (const ImportedBookmarkEntry&)entry { + if ((self = [super init])) { + NSMutableArray* paths = [[NSMutableArray alloc] init]; + for (const auto& path : entry.path) { + [paths addObject:base::SysUTF16ToNSString(path)]; + } + + _inToolbar = entry.in_toolbar; + _isFolder = entry.is_folder; + _url = net::NSURLWithGURL(entry.url); + _path = paths; + _title = base::SysUTF16ToNSString(entry.title); + _creationTime = + [NSDate dateWithTimeIntervalSince1970:entry.creation_time.ToDoubleT()]; + } + return self; +} + +- (ImportedBookmarkEntry)toChromiumImportedBookmark { + std::vector paths; + for (NSString* path in self.path) { + paths.push_back(base::SysNSStringToUTF16(path)); + } + + ImportedBookmarkEntry entry; + entry.creation_time = + base::Time::FromDoubleT([self.creationTime timeIntervalSince1970]); + entry.url = net::GURLWithNSURL(self.url); + entry.title = base::SysNSStringToUTF16(self.title); + entry.in_toolbar = self.inToolbar; + entry.path = paths; + return entry; +} +@end + +@interface BraveBookmarksImporter () { + scoped_refptr import_thread_; +} +@property(atomic) bool cancelled; // atomic +@end + +@implementation BraveBookmarksImporter +- (instancetype)init { + if ((self = [super init])) { + self.cancelled = false; + + // Create worker thread in which importer runs. + // In Chromium, this is created with `base::Thread("import_thread")` + import_thread_ = base::CreateSequencedTaskRunner( + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); + } + return self; +} + +- (void)dealloc { + [self cancel]; +} + +- (void)cancel { + self.cancelled = true; +} + +- (void)importFromFile:(NSString*)filePath + topLevelFolderName:(NSString*)folderName + automaticImport:(bool)automaticImport + withListener: + (void (^)(BraveBookmarksImporterState, + NSArray* _Nullable))listener { + base::FilePath source_file_path = base::mac::NSStringToFilePath(filePath); + + // In Chromium, this is IDS_BOOKMARK_GROUP (804) + base::string16 top_level_folder_name = base::SysNSStringToUTF16(folderName); + + auto start_import = [](BraveBookmarksImporter* weak_importer, + const base::FilePath& source_file_path, + const base::string16& top_level_folder_name, + bool automaticImport, + std::function*)> + listener) { + // Import cancelled as the importer has been deallocated + __strong BraveBookmarksImporter* importer = weak_importer; + if (!importer) { + listener(BraveBookmarksImporterStateStarted, nullptr); + listener(BraveBookmarksImporterStateCancelled, nullptr); + return; + } + + listener(BraveBookmarksImporterStateStarted, nullptr); + std::vector bookmarks; + bookmark_html_reader::ImportBookmarksFile( + base::BindRepeating( + [](BraveBookmarksImporter* importer) -> bool { + return [importer isImporterCancelled]; + }, + base::Unretained(importer)), + base::BindRepeating( + [](BraveBookmarksImporter* importer, const GURL& url) -> bool { + return [importer canImportURL:url]; + }, + base::Unretained(importer)), + source_file_path, &bookmarks, nullptr); + + if (!bookmarks.empty() && ![importer isImporterCancelled]) { + if (automaticImport) { + auto complete_import = + [](std::vector bookmarks, + const base::string16& top_level_folder_name, + std::function*)> listener) { + BookmarksImporter::AddBookmarks(top_level_folder_name, bookmarks); + listener(BraveBookmarksImporterStateAutoCompleted, nullptr); + }; + + // Import into the Profile/ChromeBrowserState on the main-thread. + base::PostTask( + FROM_HERE, {web::WebThread::UI}, + base::BindOnce(complete_import, base::Passed(std::move(bookmarks)), + top_level_folder_name, listener)); + } else { + listener(BraveBookmarksImporterStateCompleted, + [importer convertToIOSImportedBookmarks:bookmarks]); + } + } else { + listener(BraveBookmarksImporterStateCancelled, nullptr); + } + }; + + // Run the importer on the sequenced task runner. + __weak BraveBookmarksImporter* weakSelf = self; + import_thread_->PostTask( + FROM_HERE, + base::BindOnce(start_import, weakSelf, source_file_path, + top_level_folder_name, automaticImport, listener)); +} + +- (void)importFromArray:(NSArray*)bookmarks + topLevelFolderName:(NSString*)folderName + withListener:(void (^)(BraveBookmarksImporterState))listener { + // In Chromium, this is IDS_BOOKMARK_GROUP (804) + base::string16 top_level_folder_name = base::SysNSStringToUTF16(folderName); + + auto start_import = + [](BraveBookmarksImporter* weak_importer, + NSArray* bookmarks, + const base::string16& top_level_folder_name, + std::function listener) { + // Import cancelled as the importer has been deallocated + __strong BraveBookmarksImporter* importer = weak_importer; + if (!importer) { + listener(BraveBookmarksImporterStateStarted); + listener(BraveBookmarksImporterStateCancelled); + return; + } + + listener(BraveBookmarksImporterStateStarted); + BookmarksImporter::AddBookmarks( + top_level_folder_name, + [importer convertToChromiumImportedBookmarks:bookmarks]); + listener(BraveBookmarksImporterStateCompleted); + }; + + // Import into the Profile/ChromeBrowserState on the main-thread. + __weak BraveBookmarksImporter* weakSelf = self; + base::PostTask(FROM_HERE, {web::WebThread::UI}, + base::BindOnce(start_import, weakSelf, bookmarks, + top_level_folder_name, listener)); +} + +// MARK: - Private + +- (bool)isImporterCancelled { + return self.cancelled; +} + +// Returns true if |url| has a valid scheme that we allow to import. We +// filter out the URL with a unsupported scheme. +- (bool)canImportURL:(const GURL&)url { + // The URL is not valid. + if (!url.is_valid()) { + return false; + } + + // Filter out the URLs with unsupported schemes. + const char* const kInvalidSchemes[] = {"wyciwyg", "place", "about", "chrome"}; + for (size_t i = 0; i < base::size(kInvalidSchemes); ++i) { + if (url.SchemeIs(kInvalidSchemes[i])) { + return false; + } + } + + return true; +} + +// Converts an array of Chromium imported bookmarks to iOS imported bookmarks. +- (NSArray*)convertToIOSImportedBookmarks: + (const std::vector&)bookmarks { + NSMutableArray* results = + [[NSMutableArray alloc] init]; + for (const auto& bookmark : bookmarks) { + BraveImportedBookmark* imported_bookmark = [[BraveImportedBookmark alloc] + initFromChromiumImportedBookmark:bookmark]; + [results addObject:imported_bookmark]; + } + return results; +} + +// Converts an array of iOS imported bookmarks to Chromium imported bookmarks. +- (std::vector)convertToChromiumImportedBookmarks: + (NSArray*)bookmarks { + std::vector results; + for (BraveImportedBookmark* bookmark in bookmarks) { + results.push_back([bookmark toChromiumImportedBookmark]); + } + return results; +} +@end diff --git a/ios/browser/api/bookmarks/importer/favicon_reencode.h b/ios/browser/api/bookmarks/importer/favicon_reencode.h new file mode 100644 index 000000000000..acf6617b3aab --- /dev/null +++ b/ios/browser/api/bookmarks/importer/favicon_reencode.h @@ -0,0 +1,25 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_FAVICON_REENCODE_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_FAVICON_REENCODE_H_ + +#include + +#include + + +namespace importer { + +// Given raw image data, decodes the icon, re-sampling to the correct size as +// necessary, and re-encodes as PNG data in the given output vector. Returns +// true on success. +bool ReencodeFavicon(const unsigned char* src_data, + size_t src_len, + std::vector* png_data); + +} // namespace importer + +#endif // BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_FAVICON_REENCODE_H_ diff --git a/ios/browser/api/bookmarks/importer/favicon_reencode.mm b/ios/browser/api/bookmarks/importer/favicon_reencode.mm new file mode 100644 index 000000000000..0ae7452801ee --- /dev/null +++ b/ios/browser/api/bookmarks/importer/favicon_reencode.mm @@ -0,0 +1,66 @@ +/* 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/ios/browser/api/bookmarks/importer/favicon_reencode.h" +#import +#import + +namespace gfx { + //FROM: ui/gfx/geometry/size.h + const int kFaviconSize = 16; +} // namespace gfx + +namespace importer { + +bool ReencodeFavicon(const unsigned char* src_data, + size_t src_len, + std::vector* png_data) { + if (!src_data || !png_data || src_len == 0) { + return false; + } + + // Because there is no guarantee of the mime-type of the image's `src_data`, + // Chromium guesses the mime-type of the image using + // ImageDecoder::CreateByMimeType & ImageDecoder::SniffMimeTypeInternal + // Where it parses the image header to determine the type of image, + // in order to create an SkBitmap from it. Otherwise it returns a completely RED image. + + // For iOS, we don't have to do that, we can let UIImage handle it. + // If it fails, we wouldn't have been able to display such an image on iOS anyway, + // and it'll be retrieved the next time the user pulls down the image via visiting the page. + // OR the iOS side will handle it. + + //gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize) + NSData *image_data = [NSData dataWithBytes:src_data length:src_len]; + if (!image_data) { + return false; + } + + UIImage *ios_image = [UIImage imageWithData:image_data]; + if (!ios_image) { + return false; + } + + //Scale the image to the desired size: gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize) + UIGraphicsBeginImageContextWithOptions(CGSizeMake(gfx::kFaviconSize, gfx::kFaviconSize), NO, 0.0); + [ios_image drawInRect:CGRectMake(0, 0, gfx::kFaviconSize, gfx::kFaviconSize)]; + UIImage *scaled_ios_image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + if (!scaled_ios_image) { + return false; + } + + NSData *ios_png_data = UIImagePNGRepresentation(scaled_ios_image); + if (!ios_png_data || [ios_png_data length] == 0) { + return false; + } + + const unsigned char *png_bytes = static_cast([ios_png_data bytes]); + png_data->insert(png_data->begin(), png_bytes, png_bytes + [ios_png_data length]); + return true; +} + +} // namespace importer diff --git a/ios/browser/api/bookmarks/importer/imported_bookmark_entry.cc b/ios/browser/api/bookmarks/importer/imported_bookmark_entry.cc new file mode 100644 index 000000000000..daca9d13463b --- /dev/null +++ b/ios/browser/api/bookmarks/importer/imported_bookmark_entry.cc @@ -0,0 +1,25 @@ +/* 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/ios/browser/api/bookmarks/importer/imported_bookmark_entry.h" + +ImportedBookmarkEntry::ImportedBookmarkEntry() + : in_toolbar(false), + is_folder(false) {} + +ImportedBookmarkEntry::ImportedBookmarkEntry( + const ImportedBookmarkEntry& other) = default; + +ImportedBookmarkEntry::~ImportedBookmarkEntry() {} + +bool ImportedBookmarkEntry::operator==( + const ImportedBookmarkEntry& other) const { + return (in_toolbar == other.in_toolbar && + is_folder == other.is_folder && + url == other.url && + path == other.path && + title == other.title && + creation_time == other.creation_time); +} diff --git a/ios/browser/api/bookmarks/importer/imported_bookmark_entry.h b/ios/browser/api/bookmarks/importer/imported_bookmark_entry.h new file mode 100644 index 000000000000..bb7d79f4b455 --- /dev/null +++ b/ios/browser/api/bookmarks/importer/imported_bookmark_entry.h @@ -0,0 +1,30 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_IMPORTED_BOOKMARK_ENTRY_H_ +#define BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_IMPORTED_BOOKMARK_ENTRY_H_ + +#include + +#include "base/strings/string16.h" +#include "base/time/time.h" +#include "url/gurl.h" + +struct ImportedBookmarkEntry { + ImportedBookmarkEntry(); + ImportedBookmarkEntry(const ImportedBookmarkEntry& other); + ~ImportedBookmarkEntry(); + + bool operator==(const ImportedBookmarkEntry& other) const; + + bool in_toolbar; + bool is_folder; + GURL url; + std::vector path; + base::string16 title; + base::Time creation_time; +}; + +#endif // BRAVE_IOS_BROWSER_API_BOOKMARKS_IMPORTER_IMPORTED_BOOKMARK_ENTRY_H_ diff --git a/ios/browser/api/sync/BUILD.gn b/ios/browser/api/sync/BUILD.gn new file mode 100644 index 000000000000..40aa1fac19fd --- /dev/null +++ b/ios/browser/api/sync/BUILD.gn @@ -0,0 +1,36 @@ +# 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/. + +import("//build/config/ios/rules.gni") +import("//ios/build/config.gni") + +source_set("sync") { + configs += [ "//build/config/compiler:enable_arc" ] + + sources = [ + "brave_sync_api.h", + "brave_sync_api.mm", + "brave_sync_worker.h", + "brave_sync_worker.cc" + ] + + deps = [ + "//base", + "//brave/components/brave_sync", + "//brave/components/brave_sync:crypto", + "//brave/components/brave_sync:prefs", + "//components/sync/driver", + "//components/sync_device_info", + "//ios/chrome/browser", + "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/sync", + "//ios/web/public/thread", + ] + + frameworks = [ + "Foundation.framework", + "UIKit.framework" + ] +} diff --git a/ios/browser/api/sync/brave_sync_api.h b/ios/browser/api/sync/brave_sync_api.h new file mode 100644 index 000000000000..41a852268f5c --- /dev/null +++ b/ios/browser/api/sync/brave_sync_api.h @@ -0,0 +1,43 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_SYNC_BRAVE_SYNC_API_H_ +#define BRAVE_IOS_BROWSER_API_SYNC_BRAVE_SYNC_API_H_ + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +OBJC_EXPORT +@interface BraveSyncAPI : NSObject + +@property(class, readonly, strong) + BraveSyncAPI* sharedSyncAPI NS_SWIFT_NAME(shared); +@property(nonatomic) bool syncEnabled; +@property(nonatomic, readonly) bool isSyncFeatureActive; + +- (bool)resetSync; + +- (bool)isValidSyncCode:(NSString*)syncCode; + +- (NSString*)getSyncCode; + +// returns false is sync is already configured or if the sync code is invalid +- (bool)setSyncCode:(NSString*)syncCode; + +- (NSString*)syncCodeFromHexSeed:(NSString*)hexSeed; + +- (nullable UIImage*)getQRCodeImage:(CGSize)size; + +- (nullable NSString*)getDeviceListJSON; + +- (id)createSyncDeviceObserver:(void (^)())onDeviceInfoChanged; +- (id)createSyncServiceObserver:(void (^)())onSyncServiceStateChanged; +@end + +NS_ASSUME_NONNULL_END + +#endif // BRAVE_IOS_BROWSER_API_SYNC_BRAVE_SYNC_API_H_ diff --git a/ios/browser/api/sync/brave_sync_api.mm b/ios/browser/api/sync/brave_sync_api.mm new file mode 100644 index 000000000000..9d444601c70a --- /dev/null +++ b/ios/browser/api/sync/brave_sync_api.mm @@ -0,0 +1,221 @@ +/* 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/. */ + +#import "brave/ios/browser/api/sync/brave_sync_api.h" + +#import +#include +#include + +#include "base/compiler_specific.h" +#include "base/json/json_writer.h" +#include "base/memory/weak_ptr.h" +#include "base/scoped_observer.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/sys_string_conversions.h" +#include "brave/components/brave_sync/brave_sync_prefs.h" +#include "brave/components/brave_sync/crypto/crypto.h" +#import "brave/ios/browser/api/sync/brave_sync_worker.h" +#include "components/sync/driver/profile_sync_service.h" +#include "components/sync/driver/sync_service.h" +#include "components/sync/driver/sync_service_observer.h" +#include "components/sync_device_info/device_info.h" +#include "components/sync_device_info/device_info_sync_service.h" +#include "components/sync_device_info/device_info_tracker.h" +#include "components/sync_device_info/local_device_info_provider.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#include "ios/chrome/browser/sync/device_info_sync_service_factory.h" +#include "ios/chrome/browser/sync/profile_sync_service_factory.h" +#include "ios/chrome/browser/sync/sync_setup_service.h" +#include "ios/chrome/browser/sync/sync_setup_service_factory.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface BraveSyncDeviceObserver : NSObject { + std::unique_ptr _device_observer; +} +@end + +@implementation BraveSyncDeviceObserver + +- (instancetype)initWithDeviceInfoTracker:(syncer::DeviceInfoTracker*)tracker + callback:(void (^)())onDeviceInfoChanged { + if ((self = [super init])) { + _device_observer = + std::make_unique(tracker, onDeviceInfoChanged); + } + return self; +} +@end + +@interface BraveSyncServiceObserver : NSObject { + std::unique_ptr _service_tracker; +} +@end + +@implementation BraveSyncServiceObserver + +- (instancetype) + initWithProfileSyncService:(syncer::ProfileSyncService*)profileSyncService + callback:(void (^)())onSyncServiceStateChanged { + if ((self = [super init])) { + _service_tracker = std::make_unique( + profileSyncService, onSyncServiceStateChanged); + } + return self; +} +@end + +@interface BraveSyncAPI () { + std::unique_ptr _worker; + ChromeBrowserState* _chromeBrowserState; +} +@end + +@implementation BraveSyncAPI + ++ (instancetype)sharedSyncAPI { + static BraveSyncAPI* instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[BraveSyncAPI alloc] init]; + }); + return instance; +} + +- (instancetype)init { + if ((self = [super init])) { + ios::ChromeBrowserStateManager* browserStateManager = + GetApplicationContext()->GetChromeBrowserStateManager(); + _chromeBrowserState = browserStateManager->GetLastUsedBrowserState(); + _worker.reset(new BraveSyncWorker(_chromeBrowserState)); + } + return self; +} + +- (void)dealloc { + _worker.reset(); + _chromeBrowserState = NULL; +} + +- (bool)syncEnabled { + return _worker->IsSyncEnabled(); +} + +- (void)setSyncEnabled:(bool)enabled { + _worker->SetSyncEnabled(enabled); +} + +- (bool)isSyncFeatureActive { + return _worker->IsSyncFeatureActive(); +} + +- (bool)isValidSyncCode:(NSString*)syncCode { + return _worker->IsValidSyncCode(base::SysNSStringToUTF8(syncCode)); +} + +- (NSString*)getSyncCode { + std::string syncCode = _worker->GetOrCreateSyncCode(); + if (syncCode.empty()) { + return nil; + } + + return base::SysUTF8ToNSString(syncCode); +} + +- (bool)setSyncCode:(NSString*)syncCode { + return _worker->SetSyncCode(base::SysNSStringToUTF8(syncCode)); +} + +- (NSString*)syncCodeFromHexSeed:(NSString*)hexSeed { + return base::SysUTF8ToNSString( + _worker->GetSyncCodeFromHexSeed(base::SysNSStringToUTF8(hexSeed))); +} + +- (UIImage*)getQRCodeImage:(CGSize)size { + std::vector seed; + std::string sync_code = _worker->GetOrCreateSyncCode(); + if (!brave_sync::crypto::PassphraseToBytes32(sync_code, &seed)) { + return nil; + } + + // QR code version 3 can only carry 84 bytes so we hex encode 32 bytes + // seed then we will have 64 bytes input data + const std::string sync_code_hex = base::HexEncode(seed.data(), seed.size()); + + NSData* sync_code_data = [base::SysUTF8ToNSString(sync_code_hex.c_str()) + dataUsingEncoding:NSUTF8StringEncoding]; // NSISOLatin1StringEncoding + + if (!sync_code_data) { + return nil; + } + + CIFilter* filter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; + [filter setValue:sync_code_data forKey:@"inputMessage"]; + [filter setValue:@"H" forKey:@"inputCorrectionLevel"]; + + CIImage* ciImage = [filter outputImage]; + if (ciImage) { + CGFloat scaleX = size.width / ciImage.extent.size.width; + CGFloat scaleY = size.height / ciImage.extent.size.height; + CGAffineTransform transform = CGAffineTransformMakeScale(scaleX, scaleY); + ciImage = [ciImage imageByApplyingTransform:transform]; + + return [UIImage imageWithCIImage:ciImage + scale:[[UIScreen mainScreen] scale] + orientation:UIImageOrientationUp]; + } + return nil; +} + +- (NSString*)getDeviceListJSON { + auto device_list = _worker->GetDeviceList(); + auto* local_device_info = _worker->GetLocalDeviceInfo(); + + base::Value device_list_value(base::Value::Type::LIST); + + for (const auto& device : _worker->GetDeviceList()) { + auto device_value = base::Value::FromUniquePtrValue(device->ToValue()); + bool is_current_device = + local_device_info ? local_device_info->guid() == device->guid() : false; + device_value.SetBoolKey("isCurrentDevice", is_current_device); + device_value.SetStringKey("guid", device->guid()); + device_list_value.Append(std::move(device_value)); + } + + std::string json_string; + if (!base::JSONWriter::Write(device_list_value, &json_string)) { + return nil; + } + + return base::SysUTF8ToNSString(json_string); +} + +- (bool)resetSync { + return _worker->ResetSync(); +} + +- (id)createSyncDeviceObserver:(void (^)())onDeviceInfoChanged { + auto* tracker = + DeviceInfoSyncServiceFactory::GetForBrowserState(_chromeBrowserState) + ->GetDeviceInfoTracker(); + return [[BraveSyncDeviceObserver alloc] + initWithDeviceInfoTracker:tracker + callback:onDeviceInfoChanged]; +} + +- (id)createSyncServiceObserver:(void (^)())onSyncServiceStateChanged { + auto* service = + ProfileSyncServiceFactory::GetAsProfileSyncServiceForBrowserState( + _chromeBrowserState); + return [[BraveSyncServiceObserver alloc] + initWithProfileSyncService:service + callback:onSyncServiceStateChanged]; +} +@end diff --git a/ios/browser/api/sync/brave_sync_worker.cc b/ios/browser/api/sync/brave_sync_worker.cc new file mode 100644 index 000000000000..d3cd208375b0 --- /dev/null +++ b/ios/browser/api/sync/brave_sync_worker.cc @@ -0,0 +1,371 @@ +/* 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/ios/browser/api/sync/brave_sync_worker.h" + +#include +#include + +#include "base/json/json_writer.h" +#include "base/memory/weak_ptr.h" +#include "base/scoped_observer.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/sys_string_conversions.h" +#include "brave/components/brave_sync/brave_sync_prefs.h" +#include "brave/components/brave_sync/crypto/crypto.h" +#include "brave/components/sync/driver/brave_sync_profile_sync_service.h" +#include "components/sync/driver/profile_sync_service.h" +#include "components/sync/driver/sync_service.h" +#include "components/sync/driver/sync_service_observer.h" +#include "components/sync_device_info/device_info.h" +#include "components/sync_device_info/device_info_sync_service.h" +#include "components/sync_device_info/device_info_tracker.h" +#include "components/sync_device_info/local_device_info_provider.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/sync/device_info_sync_service_factory.h" +#include "ios/chrome/browser/sync/profile_sync_service_factory.h" +#include "ios/chrome/browser/sync/sync_setup_service.h" +#include "ios/chrome/browser/sync/sync_setup_service_factory.h" +#include "ios/web/public/thread/web_thread.h" + +namespace { +static const size_t SEED_BYTES_COUNT = 32u; +} // namespace + +namespace { + +// A structure which contains all the configuration information for sync. +struct SyncConfigInfo { + SyncConfigInfo(); + ~SyncConfigInfo(); + + bool encrypt_all; + bool set_new_passphrase; +}; + +SyncConfigInfo::SyncConfigInfo() + : encrypt_all(false), set_new_passphrase(false) {} + +SyncConfigInfo::~SyncConfigInfo() {} + +// Return false if we are not interested configure encryption +bool FillSyncConfigInfo(syncer::SyncService* service, + SyncConfigInfo* configuration) { + bool first_setup_in_progress = + service && !service->GetUserSettings()->IsFirstSetupComplete(); + + configuration->encrypt_all = + service->GetUserSettings()->IsEncryptEverythingEnabled(); + + bool sync_prefs_passphrase_required = + service->GetUserSettings()->IsPassphraseRequired(); + + if (!first_setup_in_progress) { + if (!configuration->encrypt_all) { + configuration->encrypt_all = true; + configuration->set_new_passphrase = true; + } else if (sync_prefs_passphrase_required) { + configuration->set_new_passphrase = false; + } else { + return false; + } + } + return true; +} + +} // namespace + +BraveSyncDeviceTracker::BraveSyncDeviceTracker( + syncer::DeviceInfoTracker* device_info_tracker, + std::function on_device_info_changed_callback) + : on_device_info_changed_callback_(on_device_info_changed_callback) { + DCHECK(device_info_tracker); + device_info_tracker_observer_.Add(device_info_tracker); +} + +BraveSyncDeviceTracker::~BraveSyncDeviceTracker() { + // Observer will be removed by ScopedObserver +} + +void BraveSyncDeviceTracker::OnDeviceInfoChange() { + if (on_device_info_changed_callback_) { + on_device_info_changed_callback_(); + } +} + +BraveSyncServiceTracker::BraveSyncServiceTracker( + syncer::ProfileSyncService* profile_sync_service, + std::function on_state_changed_callback) + : on_state_changed_callback_(on_state_changed_callback) { + DCHECK(profile_sync_service); + sync_service_observer_.Add(profile_sync_service); +} + +BraveSyncServiceTracker::~BraveSyncServiceTracker() { + // Observer will be removed by ScopedObserver +} + +void BraveSyncServiceTracker::OnStateChanged(syncer::SyncService* sync) { + if (on_state_changed_callback_) { + on_state_changed_callback_(); + } +} + +BraveSyncWorker::BraveSyncWorker(ChromeBrowserState* browser_state) + : browser_state_(browser_state) { + DCHECK_CURRENTLY_ON(web::WebThread::UI); +} + +BraveSyncWorker::~BraveSyncWorker() { + // Observer will be removed by ScopedObserver +} + +bool BraveSyncWorker::SetSyncEnabled(bool enabled) { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + auto* setup_service = + SyncSetupServiceFactory::GetForBrowserState(browser_state_); + auto* sync_service = + ProfileSyncServiceFactory::GetForBrowserState(browser_state_); + + if (!setup_service || !sync_service) { + return false; + } + + if (!sync_service_observer_.IsObserving(sync_service)) { + sync_service_observer_.Add(sync_service); + } + + setup_service->SetSyncEnabled(enabled); + + if (enabled && !sync_service->GetUserSettings()->IsFirstSetupComplete()) { + // setup_service->PrepareForFirstSyncSetup(); + // setup_service->CommitSyncChanges(); + setup_service->SetFirstSetupComplete( + syncer::SyncFirstSetupCompleteSource::ADVANCED_FLOW_CONFIRM); + } + + return true; +} + +const syncer::DeviceInfo* BraveSyncWorker::GetLocalDeviceInfo() { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + auto* device_info_service = + DeviceInfoSyncServiceFactory::GetForBrowserState(browser_state_); + + if (!device_info_service) { + return nullptr; + } + + return device_info_service->GetLocalDeviceInfoProvider() + ->GetLocalDeviceInfo(); +} + +std::vector> +BraveSyncWorker::GetDeviceList() { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + auto* device_info_service = + DeviceInfoSyncServiceFactory::GetForBrowserState(browser_state_); + + if (!device_info_service) { + return std::vector>(); + } + + syncer::DeviceInfoTracker* tracker = + device_info_service->GetDeviceInfoTracker(); + return tracker->GetAllDeviceInfo(); +} + +std::string BraveSyncWorker::GetOrCreateSyncCode() { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + auto* sync_service = GetSyncService(); + std::string sync_code; + if (sync_service) { + sync_code = sync_service->GetOrCreateSyncCode(); + } + return sync_code; +} + +bool BraveSyncWorker::IsValidSyncCode(const std::string& sync_code) { + std::vector seed; + if (!brave_sync::crypto::PassphraseToBytes32(sync_code, &seed)) { + return false; + } + return seed.size() == SEED_BYTES_COUNT; +} + +bool BraveSyncWorker::SetSyncCode(const std::string& sync_code) { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + if (sync_code.empty()) { + return false; + } + + auto* sync_service = GetSyncService(); + if (!sync_service || !sync_service->SetSyncCode(sync_code)) { + return false; + } + return true; +} + +std::string BraveSyncWorker::GetSyncCodeFromHexSeed( + const std::string& hex_code_seed) { + DCHECK(!hex_code_seed.empty()); + + std::vector bytes; + std::string sync_code_words; + if (base::HexStringToBytes(hex_code_seed, &bytes)) { + DCHECK_EQ(bytes.size(), SEED_BYTES_COUNT); + if (bytes.size(), SEED_BYTES_COUNT) { + sync_code_words = brave_sync::crypto::PassphraseFromBytes32(bytes); + if (sync_code_words.empty()) { + VLOG(1) << __func__ + << " PassphraseFromBytes32 failed for hex_code_seed"; + } + } else { + LOG(ERROR) << "wrong seed bytes " << bytes.size(); + } + + DCHECK_NE(sync_code_words, ""); + } else { + VLOG(1) << __func__ << " HexStringToBytes failed for hex_code_seed"; + } + return sync_code_words; +} + +bool BraveSyncWorker::IsFirstSetupComplete() { + syncer::SyncService* sync_service = GetSyncService(); + return sync_service && + sync_service->GetUserSettings()->IsFirstSetupComplete(); +} + +bool BraveSyncWorker::ResetSync() { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + auto* sync_service = + ProfileSyncServiceFactory::GetForBrowserState(browser_state_); + + // Do not send self deleted commit if engine is not up and running + if (!sync_service || sync_service->GetTransportState() != + syncer::SyncService::TransportState::ACTIVE) { + OnLocalDeviceInfoDeleted(); + return true; + } + + auto* local_device_info = GetLocalDeviceInfo(); + if (!local_device_info) { + // May happens when we reset the chain immediately after connection + VLOG(1) << __func__ << " no local device info, cannot reset sync now"; + return false; + } + + auto* device_info_service = + DeviceInfoSyncServiceFactory::GetForBrowserState(browser_state_); + auto* tracker = device_info_service->GetDeviceInfoTracker(); + + if (!tracker) { + return false; + } + + tracker->DeleteDeviceInfo( + local_device_info->guid(), + base::BindOnce(&BraveSyncWorker::OnLocalDeviceInfoDeleted, + weak_ptr_factory_.GetWeakPtr())); + + return true; +} + +syncer::BraveProfileSyncService* BraveSyncWorker::GetSyncService() const { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + return static_cast( + ProfileSyncServiceFactory::GetForBrowserState(browser_state_)); +} + +void BraveSyncWorker::OnStateChanged(syncer::SyncService* service) { + // If the sync engine has shutdown for some reason, just give up + if (!service || !service->IsEngineInitialized()) { + VLOG(3) << "[BraveSync] " << __func__ << " sync engine is not initialized"; + return; + } + + SyncConfigInfo configuration = {}; + if (!FillSyncConfigInfo(service, &configuration)) { + VLOG(3) << "[BraveSync] " << __func__ + << " operations with passphrase are not required"; + return; + } + + brave_sync::Prefs brave_sync_prefs(browser_state_->GetPrefs()); + std::string sync_code = brave_sync_prefs.GetSeed(); + DCHECK_NE(sync_code.size(), 0u); + + if (!service->GetUserSettings()->IsEncryptEverythingAllowed()) { + configuration.encrypt_all = false; + configuration.set_new_passphrase = false; + } + + if (configuration.encrypt_all) { + service->GetUserSettings()->EnableEncryptEverything(); + } + + bool passphrase_failed = false; + if (!sync_code.empty()) { + if (service->GetUserSettings()->IsPassphraseRequired()) { + passphrase_failed = + !service->GetUserSettings()->SetDecryptionPassphrase(sync_code); + } else if (service->GetUserSettings()->IsTrustedVaultKeyRequired()) { + passphrase_failed = true; + } else { + if (configuration.set_new_passphrase && + !service->GetUserSettings()->IsUsingSecondaryPassphrase()) { + service->GetUserSettings()->SetEncryptionPassphrase(sync_code); + } + } + } + + if (passphrase_failed || + service->GetUserSettings()->IsPassphraseRequiredForPreferredDataTypes()) { + VLOG(1) << __func__ << " setup passphrase failed"; + } +} + +void BraveSyncWorker::OnSyncShutdown(syncer::SyncService* service) { + if (sync_service_observer_.IsObserving(service)) { + sync_service_observer_.Remove(service); + } +} + +void BraveSyncWorker::OnLocalDeviceInfoDeleted() { + auto* sync_service = + ProfileSyncServiceFactory::GetForBrowserState(browser_state_); + + if (sync_service) { + sync_service->StopAndClear(); + } + + brave_sync::Prefs brave_sync_prefs(browser_state_->GetPrefs()); + brave_sync_prefs.Clear(); +} + +bool BraveSyncWorker::IsSyncEnabled() { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + auto* setup_service = + SyncSetupServiceFactory::GetForBrowserState(browser_state_); + + if (!setup_service) { + return false; + } + + return setup_service->IsSyncEnabled(); +} + +bool BraveSyncWorker::IsSyncFeatureActive() { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + auto* sync_service = + ProfileSyncServiceFactory::GetForBrowserState(browser_state_); + + if (!sync_service) { + return false; + } + + return sync_service->IsSyncFeatureActive(); +} diff --git a/ios/browser/api/sync/brave_sync_worker.h b/ios/browser/api/sync/brave_sync_worker.h new file mode 100644 index 000000000000..7bcf4be4c2ea --- /dev/null +++ b/ios/browser/api/sync/brave_sync_worker.h @@ -0,0 +1,92 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_API_SYNC_BRAVE_SYNC_WORKER_H_ +#define BRAVE_IOS_BROWSER_API_SYNC_BRAVE_SYNC_WORKER_H_ + +#include +#include +#include +#include + +#include "base/scoped_observer.h" +#include "components/sync/driver/sync_service.h" +#include "components/sync/driver/sync_service_observer.h" +#include "components/sync_device_info/device_info_sync_service.h" +#include "components/sync_device_info/device_info_tracker.h" + +class ChromeBrowserState; + +namespace syncer { +class BraveProfileSyncService; +class DeviceInfo; +class ProfileSyncService; +} // namespace syncer + +class BraveSyncDeviceTracker : public syncer::DeviceInfoTracker::Observer { + public: + BraveSyncDeviceTracker(syncer::DeviceInfoTracker* device_info_tracker, + std::function on_device_info_changed_callback); + virtual ~BraveSyncDeviceTracker(); + + private: + void OnDeviceInfoChange() override; + + std::function on_device_info_changed_callback_; + + ScopedObserver + device_info_tracker_observer_{this}; +}; + +class BraveSyncServiceTracker : public syncer::SyncServiceObserver { + public: + BraveSyncServiceTracker(syncer::ProfileSyncService* profile_sync_service, + std::function on_state_changed_callback); + ~BraveSyncServiceTracker() override; + + private: + void OnStateChanged(syncer::SyncService* sync) override; + + std::function on_state_changed_callback_; + + ScopedObserver + sync_service_observer_{this}; +}; + +class BraveSyncWorker : public syncer::SyncServiceObserver { + public: + explicit BraveSyncWorker(ChromeBrowserState* browser_state_); + ~BraveSyncWorker() override; + + bool SetSyncEnabled(bool enabled); + std::string GetOrCreateSyncCode(); + bool IsValidSyncCode(const std::string& sync_code); + bool SetSyncCode(const std::string& sync_code); + std::string GetSyncCodeFromHexSeed(const std::string& hex_seed); + const syncer::DeviceInfo* GetLocalDeviceInfo(); + std::vector> GetDeviceList(); + bool IsSyncEnabled(); + bool IsSyncFeatureActive(); + bool IsFirstSetupComplete(); + bool ResetSync(); + + private: + // syncer::SyncServiceObserver implementation. + + syncer::BraveProfileSyncService* GetSyncService() const; + void OnStateChanged(syncer::SyncService* service) override; + void OnSyncShutdown(syncer::SyncService* service) override; + + void OnLocalDeviceInfoDeleted(); + + ChromeBrowserState* browser_state_; // NOT OWNED + ScopedObserver + sync_service_observer_{this}; + base::WeakPtrFactory weak_ptr_factory_{this}; + + DISALLOW_COPY_AND_ASSIGN(BraveSyncWorker); +}; + +#endif // BRAVE_IOS_BROWSER_API_SYNC_BRAVE_SYNC_WORKER_H_ diff --git a/ios/browser/brave_web_client.h b/ios/browser/brave_web_client.h new file mode 100644 index 000000000000..a1b0afde65ad --- /dev/null +++ b/ios/browser/brave_web_client.h @@ -0,0 +1,40 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_BRAVE_WEB_CLIENT_H_ +#define BRAVE_IOS_BROWSER_BRAVE_WEB_CLIENT_H_ + +#include +#include + +#include "base/compiler_specific.h" +#include "base/macros.h" +#import "ios/web/public/web_client.h" + +class BraveWebMainParts; + +class BraveWebClient : public web::WebClient { + public: + BraveWebClient(); + ~BraveWebClient() override; + + void SetUserAgent(const std::string& user_agent); + + // WebClient implementation. + std::unique_ptr CreateWebMainParts() override; + std::string GetUserAgent(web::UserAgentType type) const override; + base::StringPiece GetDataResource( + int resource_id, + ui::ScaleFactor scale_factor) const override; + base::RefCountedMemory* GetDataResourceBytes(int resource_id) const override; + + private: + BraveWebMainParts* web_main_parts_; + std::string user_agent_; + + DISALLOW_COPY_AND_ASSIGN(BraveWebClient); +}; + +#endif // BRAVE_IOS_BROWSER_BRAVE_WEB_CLIENT_H_ diff --git a/ios/browser/brave_web_client.mm b/ios/browser/brave_web_client.mm new file mode 100644 index 000000000000..506656fb4337 --- /dev/null +++ b/ios/browser/brave_web_client.mm @@ -0,0 +1,48 @@ +/* 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/. */ + +#import "brave/ios/browser/brave_web_client.h" + +#include + +#include "base/bind.h" +#include "brave/ios/browser/brave_web_main_parts.h" +#include "ui/base/resource/resource_bundle.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +BraveWebClient::BraveWebClient() : web_main_parts_(nullptr) {} + +BraveWebClient::~BraveWebClient() { +} + +std::unique_ptr BraveWebClient::CreateWebMainParts() { + auto web_main_parts = std::make_unique(); + web_main_parts_ = web_main_parts.get(); + return web_main_parts; +} + +void BraveWebClient::SetUserAgent(const std::string& user_agent) { + user_agent_ = user_agent; +} + +std::string BraveWebClient::GetUserAgent(web::UserAgentType type) const { + return user_agent_; +} + +base::StringPiece BraveWebClient::GetDataResource( + int resource_id, + ui::ScaleFactor scale_factor) const { + return ui::ResourceBundle::GetSharedInstance().GetRawDataResourceForScale( + resource_id, scale_factor); +} + +base::RefCountedMemory* BraveWebClient::GetDataResourceBytes( + int resource_id) const { + return ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes( + resource_id); +} diff --git a/ios/browser/brave_web_main_parts.h b/ios/browser/brave_web_main_parts.h new file mode 100644 index 000000000000..668fd87edcdc --- /dev/null +++ b/ios/browser/brave_web_main_parts.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2019 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_IOS_BROWSER_BRAVE_WEB_MAIN_PARTS_H_ +#define BRAVE_IOS_BROWSER_BRAVE_WEB_MAIN_PARTS_H_ + +#include + +#include "base/macros.h" +#include "ios/chrome/browser/ios_chrome_field_trials.h" +#include "ios/web/public/init/web_main_parts.h" + +class ApplicationContextImpl; +class PrefService; + +namespace base { +class FieldTrialList; +} + +class BraveWebMainParts : public web::WebMainParts { + public: + BraveWebMainParts(); + ~BraveWebMainParts() override; + + private: + // web::WebMainParts implementation. + void PreMainMessageLoopStart() override; + void PreCreateThreads() override; + void PreMainMessageLoopRun() override; + void PostMainMessageLoopRun() override; + void PostDestroyThreads() override; + void SetupFieldTrials(); + + std::unique_ptr application_context_; + + // Statistical testing infrastructure for the entire browser. NULL until + // SetUpMetricsAndFieldTrials is called. + std::unique_ptr field_trial_list_; + + PrefService* local_state_; + + IOSChromeFieldTrials ios_field_trials_; + + DISALLOW_COPY_AND_ASSIGN(BraveWebMainParts); +}; + +#endif // BRAVE_IOS_BROWSER_BRAVE_WEB_MAIN_PARTS_H_ diff --git a/ios/browser/brave_web_main_parts.mm b/ios/browser/brave_web_main_parts.mm new file mode 100644 index 000000000000..39d7cf8dda66 --- /dev/null +++ b/ios/browser/brave_web_main_parts.mm @@ -0,0 +1,132 @@ +/* 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/ios/browser/brave_web_main_parts.h" + +#include "base/base_switches.h" +#include "base/metrics/user_metrics.h" +#include "base/path_service.h" +#include "base/sequenced_task_runner.h" +#include "base/task/post_task.h" +#include "base/task/thread_pool.h" +#include "components/flags_ui/pref_service_flags_storage.h" +#include "components/metrics_services_manager/metrics_services_manager.h" +#include "components/variations/service/variations_service.h" +#include "ios/chrome/browser/application_context_impl.h" +#include "ios/chrome/browser/browser_state/browser_state_keyed_service_factories.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#include "ios/chrome/browser/chrome_paths.h" +#include "ios/chrome/browser/flags/about_flags.h" +#include "ios/web/public/thread/web_task_traits.h" +#include "ios/web/public/thread/web_thread.h" +#include "ui/base/l10n/l10n_util_mac.h" +#include "ui/base/resource/resource_bundle.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +BraveWebMainParts::BraveWebMainParts() {} + +BraveWebMainParts::~BraveWebMainParts() {} + +void BraveWebMainParts::PreMainMessageLoopStart() { + l10n_util::OverrideLocaleWithCocoaLocale(); + + const std::string loaded_locale = + ui::ResourceBundle::InitSharedInstanceWithLocale( + std::string(), nullptr, ui::ResourceBundle::LOAD_COMMON_RESOURCES); + CHECK(!loaded_locale.empty()); + + base::FilePath resources_pack_path; + base::PathService::Get(ios::FILE_RESOURCES_PACK, &resources_pack_path); + ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath( + resources_pack_path, ui::SCALE_FACTOR_100P); +} + +void BraveWebMainParts::PreCreateThreads() { + scoped_refptr local_state_task_runner = + base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); + + base::FilePath local_state_path; + CHECK(base::PathService::Get(ios::FILE_LOCAL_STATE, &local_state_path)); + application_context_.reset(new ApplicationContextImpl( + local_state_task_runner.get(), *base::CommandLine::ForCurrentProcess(), + l10n_util::GetLocaleOverride())); + DCHECK_EQ(application_context_.get(), GetApplicationContext()); + + // Initialize local state. + local_state_ = application_context_->GetLocalState(); + DCHECK(local_state_); + + flags_ui::PrefServiceFlagsStorage flags_storage( + application_context_->GetLocalState()); + ConvertFlagsToSwitches(&flags_storage, + base::CommandLine::ForCurrentProcess()); + + SetupFieldTrials(); + + // variations::InitCrashKeys(); + // metrics::EnableExpiryChecker(::kExpiredHistogramsHashes, + // ::kNumExpiredHistograms); + + application_context_->PreCreateThreads(); +} + +void BraveWebMainParts::SetupFieldTrials() { + base::SetRecordActionTaskRunner( + base::CreateSingleThreadTaskRunner({web::WebThread::UI})); + + // Initialize FieldTrialList to support FieldTrials that use one-time + // randomization. + DCHECK(!field_trial_list_); + field_trial_list_.reset( + new base::FieldTrialList(application_context_->GetMetricsServicesManager() + ->CreateEntropyProvider())); + + std::unique_ptr feature_list(new base::FeatureList); + + // Associate parameters chosen in about:flags and create trial/group for them. + flags_ui::PrefServiceFlagsStorage flags_storage( + application_context_->GetLocalState()); + std::vector variation_ids; + RegisterAllFeatureVariationParameters(&flags_storage, feature_list.get()); + + // On iOS, GPU benchmarking is not supported. So, pass in a dummy value for + // the name of the switch that enables gpu benchmarking. + application_context_->GetVariationsService()->SetupFieldTrials( + "dummy-enable-gpu-benchmarking", switches::kEnableFeatures, + switches::kDisableFeatures, variation_ids, + std::vector(), + std::move(feature_list), &ios_field_trials_); +} + +void BraveWebMainParts::PreMainMessageLoopRun() { + application_context_->PreMainMessageLoopRun(); + + // ContentSettingsPattern need to be initialized before creating the + // ChromeBrowserState. + ContentSettingsPattern::SetNonWildcardDomainNonPortSchemes(nullptr, 0); + + // Ensure that the browser state is initialized. + EnsureBrowserStateKeyedServiceFactoriesBuilt(); + ios::ChromeBrowserStateManager* browser_state_manager = + application_context_->GetChromeBrowserStateManager(); + ChromeBrowserState* last_used_browser_state = + browser_state_manager->GetLastUsedBrowserState(); + + ALLOW_UNUSED_LOCAL(last_used_browser_state); +} + +void BraveWebMainParts::PostMainMessageLoopRun() { + application_context_->StartTearDown(); +} + +void BraveWebMainParts::PostDestroyThreads() { + application_context_->PostDestroyThreads(); +} diff --git a/ios/browser/metrics/BUILD.gn b/ios/browser/metrics/BUILD.gn new file mode 100644 index 000000000000..740335408ab4 --- /dev/null +++ b/ios/browser/metrics/BUILD.gn @@ -0,0 +1,24 @@ +# 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/. + +import("//build/config/ios/rules.gni") +import("//ios/build/config.gni") + +source_set("metrics") { + configs += [ "//build/config/compiler:enable_arc" ] + + sources = [ + "ios_brave_metrics_services_manager_client.h", + "ios_brave_metrics_services_manager_client.mm", + ] + + deps = [ + "//base", + "//ios/chrome/browser/metrics", + "//components/metrics", + "//components/prefs", + "//components/rappor", + ] +} diff --git a/ios/browser/metrics/ios_brave_metrics_services_manager_client.h b/ios/browser/metrics/ios_brave_metrics_services_manager_client.h new file mode 100644 index 000000000000..b3c62b7c1352 --- /dev/null +++ b/ios/browser/metrics/ios_brave_metrics_services_manager_client.h @@ -0,0 +1,40 @@ +/* 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/. */ + +#ifndef BRAVE_IOS_BROWSER_METRICS_IOS_BRAVE_METRICS_SERVICES_MANAGER_CLIENT_H_ +#define BRAVE_IOS_BROWSER_METRICS_IOS_BRAVE_METRICS_SERVICES_MANAGER_CLIENT_H_ + +#include +#include "base/macros.h" +#include "ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.h" + +class PrefService; + +namespace metrics { +class EnabledStateProvider; +class MetricsStateManager; +} + +// Provides an //ios/brave-specific implementation of +// MetricsServicesManagerClient. +class IOSBraveMetricsServicesManagerClient + : public IOSChromeMetricsServicesManagerClient { + public: + explicit IOSBraveMetricsServicesManagerClient(PrefService* local_state); + ~IOSBraveMetricsServicesManagerClient() override; + + private: + // metrics_services_manager::MetricsServicesManagerClient: + std::unique_ptr CreateRapporServiceImpl() override; + std::unique_ptr CreateMetricsServiceClient() + override; + bool IsMetricsReportingEnabled() override; + bool IsMetricsConsentGiven() override; + bool IsOffTheRecordSessionActive() override; + + DISALLOW_COPY_AND_ASSIGN(IOSBraveMetricsServicesManagerClient); +}; + +#endif // BRAVE_IOS_BROWSER_METRICS_IOS_BRAVE_METRICS_SERVICES_MANAGER_CLIENT_H_ diff --git a/ios/browser/metrics/ios_brave_metrics_services_manager_client.mm b/ios/browser/metrics/ios_brave_metrics_services_manager_client.mm new file mode 100644 index 000000000000..3cedfa5bc806 --- /dev/null +++ b/ios/browser/metrics/ios_brave_metrics_services_manager_client.mm @@ -0,0 +1,43 @@ +/* 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/ios/browser/metrics/ios_brave_metrics_services_manager_client.h" + +#include "components/metrics/metrics_service_client.h" +#include "components/prefs/pref_service.h" +#include "components/rappor/rappor_service_impl.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +IOSBraveMetricsServicesManagerClient::IOSBraveMetricsServicesManagerClient( + PrefService* local_state) + : IOSChromeMetricsServicesManagerClient(local_state) {} + +IOSBraveMetricsServicesManagerClient:: + ~IOSBraveMetricsServicesManagerClient() = default; + +std::unique_ptr +IOSBraveMetricsServicesManagerClient::CreateRapporServiceImpl() { + return nullptr; +} + +std::unique_ptr +IOSBraveMetricsServicesManagerClient::CreateMetricsServiceClient() { + return nullptr; +} + +bool IOSBraveMetricsServicesManagerClient::IsMetricsReportingEnabled() { + return false; +} + +bool IOSBraveMetricsServicesManagerClient::IsMetricsConsentGiven() { + return false; +} + +bool IOSBraveMetricsServicesManagerClient::IsOffTheRecordSessionActive() { + return false; +} diff --git a/patches/ios-chrome-browser-prefs-browser_prefs.mm.patch b/patches/ios-chrome-browser-prefs-browser_prefs.mm.patch new file mode 100644 index 000000000000..6e83fa563239 --- /dev/null +++ b/patches/ios-chrome-browser-prefs-browser_prefs.mm.patch @@ -0,0 +1,12 @@ +diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm +index 3a3c235d35be70f98c77659a6233169d85c260e3..da586b7289746f6d24c734aff225108ad9813e07 100644 +--- a/ios/chrome/browser/prefs/browser_prefs.mm ++++ b/ios/chrome/browser/prefs/browser_prefs.mm +@@ -233,6 +233,7 @@ void RegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) { + + registry->RegisterIntegerPref(kPasswordManagerOnboardingState, 0); + registry->RegisterBooleanPref(kWasOnboardingFeatureCheckedBefore, false); ++ BRAVE_REGISTER_BROWSER_STATE_PREFS + } + + // This method should be periodically pruned of year+ old migrations. diff --git a/patches/ios-chrome-browser-sync-profile_sync_service_factory.cc.patch b/patches/ios-chrome-browser-sync-profile_sync_service_factory.cc.patch new file mode 100644 index 000000000000..13e887f1e85e --- /dev/null +++ b/patches/ios-chrome-browser-sync-profile_sync_service_factory.cc.patch @@ -0,0 +1,13 @@ +diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc +index 0d0aa87eb02fefcac02d2360233192b9837b3ee9..e8aa0db748b605fdd6d477a9e60415f97d1bb45a 100644 +--- a/ios/chrome/browser/sync/profile_sync_service_factory.cc ++++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc +@@ -184,7 +184,7 @@ ProfileSyncServiceFactory::BuildServiceInstanceFor( + } + + auto pss = +- std::make_unique(std::move(init_params)); ++ BRAVE_BUILD_SERVICE_INSTANCE_FOR + pss->Initialize(); + + // Hook PSS into PersonalDataManager (a circular dependency). diff --git a/vendor/brave-ios/.DS_Store b/vendor/brave-ios/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b076bdd7b5c7fac14408e0ad7416849fd6c088de GIT binary patch literal 8196 zcmeHM&2AGh5FR)E*#rRrAyRSL3lfL6$`5Tp2q}beh{OSr0tY~CHVMh1WH(ASjUc4T zg?A`|7vN2hcmN)R2Y}B%jds0h=>=L9kK`GzJ!8k;jP0Eb5wX&so+DZ&A`6Af^aZdP z#QS-P(VS|z4#{9oe$8q74xZ96UDIF?FbEg~3<3rLgTUE90CzSg>xg?__8M*wFbMpY z2=Md4M&Yuk0MP|ByCsfGjFGkrFK+CQTuwDN`v1Q@I0^=IAdf z{fU&)oS2vyaw+9qL5KU>R+UODCV7ebj6%*gm5&J*F-E z+9rA0Tt7Aa6xGP54t2pjtkt7nCQ1h(lxEsE!+uwN8TsyX+ipL|W`D4`#QehIl4Yf= z)Wy{6O3NQsf@(16m#V#&{OL(GXgR9B?fdO%z3M!78^fLSwTHeJR9&yp6UJ`60hL!T zT(9mAOa8#C_r*9B*WYvE>slDup|^0>s?gWn%ERDT{g8XUowj>2qfs9I$mI&$H+Ku`EA~cV zJ?5JOtO<0aZ$6 z{XR3XLBJsJ_Yq+8Ta~R6<~e-R)2HOQwvDoj!inomq!cD#A{~bm={V%{4@1;#sB)X4 kk`pP>0{Z740*-xWGWY-C+y6=4FwOlx-aiRWXYv034bY0MH~;_u literal 0 HcmV?d00001 diff --git a/vendor/brave-ios/Ads/BATAdNotification.h b/vendor/brave-ios/Ads/BATAdNotification.h index cc35be6e53cb..8cd0ad70db0f 100644 --- a/vendor/brave-ios/Ads/BATAdNotification.h +++ b/vendor/brave-ios/Ads/BATAdNotification.h @@ -18,6 +18,7 @@ typedef NS_ENUM(NSInteger, BATAdsConfirmationType) { BATAdsConfirmationTypeConversion // = ads::ConfirmationType::kConversion } NS_SWIFT_NAME(ConfirmationType); +OBJC_EXPORT NS_SWIFT_NAME(AdsNotification) @interface BATAdNotification : NSObject @property (nonatomic, readonly, copy) NSString *uuid; @@ -30,6 +31,7 @@ NS_SWIFT_NAME(AdsNotification) @property (nonatomic, readonly, copy) NSString *targetURL; @end +OBJC_EXPORT @interface BATAdNotification (MyFirstAd) + (instancetype)customAdWithTitle:(NSString *)title body:(NSString *)body diff --git a/vendor/brave-ios/Ads/BATBraveAds.h b/vendor/brave-ios/Ads/BATBraveAds.h index 0f9c087cd96d..ce867f3ee799 100644 --- a/vendor/brave-ios/Ads/BATBraveAds.h +++ b/vendor/brave-ios/Ads/BATBraveAds.h @@ -22,6 +22,7 @@ NS_ASSUME_NONNULL_BEGIN @class BATAdNotification, BATBraveAds, BATBraveLedger; +OBJC_EXPORT NS_SWIFT_NAME(BraveAdsNotificationHandler) @protocol BATBraveAdsNotificationHandler @required @@ -35,6 +36,7 @@ NS_SWIFT_NAME(BraveAdsNotificationHandler) - (void)clearNotificationWithIdentifier:(NSString *)identifier; @end +OBJC_EXPORT NS_SWIFT_NAME(BraveAds) @interface BATBraveAds : NSObject diff --git a/vendor/brave-ios/Ads/BATBraveAds.mm b/vendor/brave-ios/Ads/BATBraveAds.mm index 4a7bf4d3da87..7297a84a7ebc 100644 --- a/vendor/brave-ios/Ads/BATBraveAds.mm +++ b/vendor/brave-ios/Ads/BATBraveAds.mm @@ -20,8 +20,10 @@ #import #import +#include "base/sequenced_task_runner.h" #import "base/strings/sys_string_conversions.h" -#import "brave/base/containers/utils.h" +#include "base/task/post_task.h" +#include "base/task_runner_util.h" #import "base/base64.h" #import "RewardsLogging.h" @@ -50,6 +52,23 @@ + (void)__objc_setter:(__type)newValue { ads::__cpp_var = newValue; } static NSString * const kAutoDetectedAdsSubdivisionTargetingCodePrefKey = [NSString stringWithUTF8String:ads::prefs::kAutoDetectedAdsSubdivisionTargetingCode]; static NSString * const kUserModelMetadataPrefKey = @"BATUserModelMetadata"; +namespace { + +ads::DBCommandResponsePtr RunDBTransactionOnTaskRunner( + ads::DBTransactionPtr transaction, + ads::Database* database) { + auto response = ads::DBCommandResponse::New(); + if (!database) { + response->status = ads::DBCommandResponse::Status::RESPONSE_ERROR; + } else { + database->RunTransaction(std::move(transaction), response.get()); + } + + return response; +} + +} // namespace + @interface BATAdNotification () - (instancetype)initWithNotificationInfo:(const ads::AdNotificationInfo&)info; @end @@ -58,6 +77,7 @@ @interface BATBraveAds () { NativeAdsClient *adsClient; ads::Ads *ads; ads::Database *adsDatabase; + scoped_refptr databaseQueue; nw_path_monitor_t networkMonitor; dispatch_queue_t monitorQueue; @@ -67,7 +87,6 @@ @interface BATBraveAds () { @property (nonatomic, copy) NSString *storagePath; @property (nonatomic) dispatch_queue_t prefsWriteThread; @property (nonatomic) NSMutableDictionary *prefs; -@property (nonatomic) dispatch_queue_t databaseQueue; @property (nonatomic, copy) NSDictionary *userModelMetadata; @property (nonatomic) NSTimer *updateUserModelTimer; @property (nonatomic) int64_t userModelRetryCount; @@ -101,6 +120,11 @@ - (instancetype)initWithStateStoragePath:(NSString *)path self.userModelRetryCount = 1; + databaseQueue = base::CreateSequencedTaskRunner( + {base::ThreadPool(), base::MayBlock(), + base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); + // Add notifications for standard app foreground/background [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(applicationDidBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; @@ -115,6 +139,11 @@ - (void)dealloc [NSNotificationCenter.defaultCenter removeObserver:self]; if (networkMonitor) { nw_path_monitor_cancel(networkMonitor); } + + if (adsDatabase) { + databaseQueue->DeleteSoon(FROM_HERE, adsDatabase); + } + if (ads != nil) { delete ads; delete adsClient; @@ -186,8 +215,6 @@ + (void)setBuildChannel:(BATBraveAdsBuildChannel *)buildChannel - (void)initializeIfAdsEnabled { if (![self isAdsServiceRunning] && self.enabled) { - self.databaseQueue = dispatch_queue_create("com.rewards.ads.db-transactions", DISPATCH_QUEUE_SERIAL); - const auto* dbPath = [self adsDatabasePath].UTF8String; adsDatabase = new ads::Database(base::FilePath(dbPath)); @@ -985,22 +1012,20 @@ - (void)setAutoDetectedAdsSubdivisionTargetingCode:(const std::string &)subdivis self.autoDetectedSubdivisionTargetingCode = [NSString stringWithCString:subdivision_targeting_code.c_str() encoding:[NSString defaultCStringEncoding]]; } -- (void)runDBTransaction:(ads::DBTransactionPtr)transaction callback:(ads::RunDBTransactionCallback)callback -{ - if (!adsDatabase || transaction.get() == nullptr) { - auto response = ads::DBCommandResponse::New(); - response->status = ads::DBCommandResponse::Status::RESPONSE_ERROR; - callback(std::move(response)); - } else { - __block auto transactionClone = transaction->Clone(); - dispatch_async(self.databaseQueue, ^{ - __block auto response = ads::DBCommandResponse::New(); - adsDatabase->RunTransaction(std::move(transactionClone), response.get()); - dispatch_async(dispatch_get_main_queue(), ^{ - callback(std::move(response)); - }); - }); - } +- (void)runDBTransaction:(ads::DBTransactionPtr)transaction + callback:(ads::RunDBTransactionCallback)callback +{ + __weak BATBraveAds* weakSelf = self; + base::PostTaskAndReplyWithResult( + databaseQueue.get(), + FROM_HERE, + base::BindOnce(&RunDBTransactionOnTaskRunner, + base::Passed(std::move(transaction)), + adsDatabase), + base::BindOnce(^(ads::DBCommandResponsePtr response) { + if (weakSelf) + callback(std::move(response)); + })); } - (void)onAdRewardsChanged diff --git a/vendor/brave-ios/BATBraveRewards.h b/vendor/brave-ios/BATBraveRewards.h index e1e9b9ce9bbe..0c5d9f1be326 100644 --- a/vendor/brave-ios/BATBraveRewards.h +++ b/vendor/brave-ios/BATBraveRewards.h @@ -10,6 +10,7 @@ NS_ASSUME_NONNULL_BEGIN /// Configuration around brave rewards for ads & ledger +OBJC_EXPORT NS_SWIFT_NAME(BraveRewardsConfiguration) @interface BATBraveRewardsConfiguration : NSObject @@ -48,6 +49,7 @@ NS_SWIFT_NAME(BraveRewardsConfiguration) @end +OBJC_EXPORT NS_SWIFT_NAME(BraveRewardsDelegate) @protocol BATBraveRewardsDelegate @required @@ -69,6 +71,7 @@ NS_SWIFT_NAME(BraveRewardsDelegate) /// A container for handling Brave Rewards. Use `ads` to handle how many ads the users see, /// when to display them. Use `ledger` to manage interactions between the users wallet & publishers +OBJC_EXPORT NS_SWIFT_NAME(BraveRewards) @interface BATBraveRewards : NSObject @@ -90,6 +93,7 @@ NS_SWIFT_NAME(BraveRewards) @end +OBJC_EXPORT @interface BATBraveRewards (Reporting) /// Report that a tab with a given id was updated diff --git a/vendor/brave-ios/BUILD.gn b/vendor/brave-ios/BUILD.gn index e2ba0abbd5d8..48f0dc7b7222 100644 --- a/vendor/brave-ios/BUILD.gn +++ b/vendor/brave-ios/BUILD.gn @@ -4,6 +4,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. import("//build/config/ios/rules.gni") +import("//brave/ios/app/headers.gni") config("internal_config") { visibility = [ @@ -19,6 +20,7 @@ config("internal_config") { "-Wno-objc-property-synthesis", "-Wno-sign-compare", ] + ldflags = [ "-Wl,-no_compact_unwind" ] include_dirs = [ ".", "Ads", @@ -53,10 +55,9 @@ ios_framework_bundle("brave_rewards_ios_framework") { configs += [ ":internal_config" ] configs += [ "//build/config/compiler:enable_arc" ] - configs -= [ "//build/config/gcc:symbol_visibility_hidden" ] deps = [ - "//brave/base:base", + "//brave/ios/app", "//brave/vendor/bat-native-ledger", "//brave/vendor/bat-native-ads", "//net:net", @@ -154,13 +155,16 @@ ios_framework_bundle("brave_rewards_ios_framework") { "$target_gen_dir/ads.mojom.objc.h", ] + public_headers += brave_core_public_headers + frameworks = [ "Foundation.framework", "UIKit.framework", "Security.framework", "CoreData.framework", "SystemConfiguration.framework", - "Network.framework" + "Network.framework", + "CoreImage.framework" ] } diff --git a/vendor/brave-ios/BraveRewards.h b/vendor/brave-ios/BraveRewards.h index 9823fdadcbee..dfc6c77ac79f 100644 --- a/vendor/brave-ios/BraveRewards.h +++ b/vendor/brave-ios/BraveRewards.h @@ -20,3 +20,15 @@ FOUNDATION_EXPORT const unsigned char BraveRewardsVersionString[]; #import #import #import + +// brave-core +#import + +// Sync +#import + +// Bookmarks +#import +#import +#import +#import diff --git a/vendor/brave-ios/Ledger/BATBraveLedger.h b/vendor/brave-ios/Ledger/BATBraveLedger.h index 1bc34af8cbd6..373593b12776 100644 --- a/vendor/brave-ios/Ledger/BATBraveLedger.h +++ b/vendor/brave-ios/Ledger/BATBraveLedger.h @@ -15,14 +15,15 @@ NS_ASSUME_NONNULL_BEGIN typedef void (^BATFaviconFetcher)(NSURL *pageURL, void (^completion)(NSURL * _Nullable faviconURL)); /// The error domain for ledger related errors -extern NSString * const BATBraveLedgerErrorDomain NS_SWIFT_NAME(BraveLedgerErrorDomain); +OBJC_EXPORT NSString * const BATBraveLedgerErrorDomain NS_SWIFT_NAME(BraveLedgerErrorDomain); -extern NSNotificationName const BATBraveLedgerNotificationAdded NS_SWIFT_NAME(BraveLedger.NotificationAdded); +OBJC_EXPORT NSNotificationName const BATBraveLedgerNotificationAdded NS_SWIFT_NAME(BraveLedger.NotificationAdded); typedef NSString *BATBraveGeneralLedgerNotificationID NS_SWIFT_NAME(GeneralLedgerNotificationID) NS_STRING_ENUM; -extern BATBraveGeneralLedgerNotificationID const BATBraveGeneralLedgerNotificationIDWalletNowVerified; -extern BATBraveGeneralLedgerNotificationID const BATBraveGeneralLedgerNotificationIDWalletDisconnected; +OBJC_EXPORT BATBraveGeneralLedgerNotificationID const BATBraveGeneralLedgerNotificationIDWalletNowVerified; +OBJC_EXPORT BATBraveGeneralLedgerNotificationID const BATBraveGeneralLedgerNotificationIDWalletDisconnected; +OBJC_EXPORT NS_SWIFT_NAME(BraveLedger) @interface BATBraveLedger : NSObject diff --git a/vendor/brave-ios/Ledger/BATBraveLedger.mm b/vendor/brave-ios/Ledger/BATBraveLedger.mm index a573c938ec1d..9ade201a76d1 100644 --- a/vendor/brave-ios/Ledger/BATBraveLedger.mm +++ b/vendor/brave-ios/Ledger/BATBraveLedger.mm @@ -35,6 +35,9 @@ #import "base/ios/ios_util.h" #import "base/base64.h" #import "base/command_line.h" +#include "base/sequenced_task_runner.h" +#include "base/task/post_task.h" +#include "base/task_runner_util.h" #import "RewardsLogging.h" @@ -94,11 +97,30 @@ typedef NS_ENUM(NSInteger, BATLedgerDatabaseMigrationType) { BATLedgerDatabaseMigrationTypeNone }; +namespace { + +ledger::type::DBCommandResponsePtr RunDBTransactionOnTaskRunner( + ledger::type::DBTransactionPtr transaction, + ledger::LedgerDatabase* database) { + auto response = ledger::type::DBCommandResponse::New(); + if (!database) { + response->status = ledger::type::DBCommandResponse::Status::RESPONSE_ERROR; + } else { + database->RunTransaction(std::move(transaction), response.get()); + } + + return response; +} + +} // namespace + @interface BATBraveLedger () { NativeLedgerClient *ledgerClient; ledger::Ledger *ledger; ledger::LedgerDatabase *rewardsDatabase; + scoped_refptr databaseQueue; } + @property (nonatomic, copy) NSString *storagePath; @property (nonatomic) BATRewardsParameters *rewardsParameters; @property (nonatomic) BATBalance *balance; @@ -121,8 +143,6 @@ @interface BATBraveLedger () { @property (nonatomic, getter=isInitializingWallet) BOOL initializingWallet; @property (nonatomic) BATLedgerDatabaseMigrationType migrationType; -@property (nonatomic) dispatch_queue_t databaseQueue; - /// Notifications @property (nonatomic) NSMutableArray *mNotifications; @@ -159,22 +179,18 @@ - (instancetype)initWithStateStoragePath:(NSString *)path self.prefs[kMigrationSucceeded] = @(NO); [self savePrefs]; } - - const auto pathToICUDTL = [[NSBundle bundleForClass:[BATBraveLedger class]] pathForResource:@"icudtl" ofType:@"dat"]; - base::ios::OverridePathOfEmbeddedICU(pathToICUDTL.UTF8String); - if (!base::i18n::InitializeICU()) { - BLOG(0, @"Failed to initialize ICU data"); - } - + const auto args = [NSProcessInfo processInfo].arguments; const char *argv[args.count]; for (NSInteger i = 0; i < args.count; i++) { argv[i] = args[i].UTF8String; } - base::CommandLine::Init(args.count, argv); - - self.databaseQueue = dispatch_queue_create("com.rewards.db-transactions", DISPATCH_QUEUE_SERIAL); - + + databaseQueue = base::CreateSequencedTaskRunner( + {base::ThreadPool(), base::MayBlock(), + base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); + const auto* dbPath = [self rewardsDatabasePath].UTF8String; rewardsDatabase = ledger::LedgerDatabase::CreateInstance(base::FilePath(dbPath)); @@ -182,12 +198,13 @@ - (instancetype)initWithStateStoragePath:(NSString *)path ledger = ledger::Ledger::CreateInstance(ledgerClient); self.migrationType = BATLedgerDatabaseMigrationTypeDefault; - BOOL needsMigration = [self databaseNeedsMigration]; - if (needsMigration) { - [BATLedgerDatabase deleteCoreDataServerPublisherList:nil]; - } - [self initializeLedgerService:needsMigration]; - + [self databaseNeedsMigration:^(BOOL needsMigration) { + if (needsMigration) { + [BATLedgerDatabase deleteCoreDataServerPublisherList:nil]; + } + [self initializeLedgerService:needsMigration]; + }]; + // Add notifications for standard app foreground/background [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(applicationDidBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; @@ -206,9 +223,11 @@ - (void)dealloc [NSNotificationCenter.defaultCenter removeObserver:self]; [self.notificationStartupTimer invalidate]; + if (rewardsDatabase) { + databaseQueue->DeleteSoon(FROM_HERE, rewardsDatabase); + } delete ledger; delete ledgerClient; - delete rewardsDatabase; } - (void)initializeLedgerService:(BOOL)executeMigrateScript @@ -264,20 +283,23 @@ - (void)initializeLedgerService:(BOOL)executeMigrateScript }); } -- (BOOL)databaseNeedsMigration +- (void)databaseNeedsMigration:(void (^)(BOOL needsMigration))completion { // Check if we even have a DB to migrate if (!DataController.defaultStoreExists) { - return NO; + completion(NO); + return; } // Have we set the pref saying ledger has alaready initialized successfully? if ([self.prefs[kMigrationSucceeded] boolValue]) { - return NO; + completion(NO); + return; } // Can we even check the DB if (!rewardsDatabase) { BLOG(3, @"DB: No rewards database object"); - return YES; + completion(YES); + return; } // Check integrity of the new DB. Safe to assume if `publisher_info` table // exists, then all the others do as well. @@ -287,33 +309,34 @@ - (BOOL)databaseNeedsMigration command->command = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'publisher_info';"; command->record_bindings = { ledger::type::DBCommand::RecordBindingType::STRING_TYPE }; transaction->commands.push_back(command->Clone()); - - auto response = ledger::type::DBCommandResponse::New(); - rewardsDatabase->RunTransaction(std::move(transaction), response.get()); - - // Failed to even run the check, tables probably don't exist, - // restart from scratch - if (response->status != ledger::type::DBCommandResponse::Status::RESPONSE_OK) { - [self resetRewardsDatabase]; - BLOG(3, @"DB: Failed to run transaction with status: %d", response->status); - return YES; - } - - const auto record = std::move(response->result->get_records()); - // sqlite_master table exists, but the publisher_info table doesn't exist? - // Restart from scratch - if (record.empty() || record.front()->fields.empty()) { - [self resetRewardsDatabase]; - BLOG(3, @"DB: Migrate because we couldnt find tables in sqlite_master"); - return YES; - } - - // Tables exist so migration has happened already, but somehow the flag wasn't - // saved. - self.prefs[kMigrationSucceeded] = @(YES); - [self savePrefs]; - - return NO; + + [self runDBTransaction:std::move(transaction) callback:^(ledger::type::DBCommandResponsePtr response){ + // Failed to even run the check, tables probably don't exist, + // restart from scratch + if (response->status != ledger::type::DBCommandResponse::Status::RESPONSE_OK) { + [self resetRewardsDatabase]; + BLOG(3, @"DB: Failed to run transaction with status: %d", response->status); + completion(YES); + return; + } + + const auto record = std::move(response->result->get_records()); + // sqlite_master table exists, but the publisher_info table doesn't exist? + // Restart from scratch + if (record.empty() || record.front()->fields.empty()) { + [self resetRewardsDatabase]; + BLOG(3, @"DB: Migrate because we couldnt find tables in sqlite_master"); + completion(YES); + return; + } + + // Tables exist so migration has happened already, but somehow the flag wasn't + // saved. + self.prefs[kMigrationSucceeded] = @(YES); + [self savePrefs]; + + completion(NO); + }]; } - (NSString *)rewardsDatabasePath @@ -1825,20 +1848,17 @@ - (void)reconcileStampReset - (void)runDBTransaction:(ledger::type::DBTransactionPtr)transaction callback:(ledger::client::RunDBTransactionCallback)callback { - if (!rewardsDatabase || transaction.get() == nullptr) { - auto response = ledger::type::DBCommandResponse::New(); - response->status = ledger::type::DBCommandResponse::Status::RESPONSE_ERROR; - callback(std::move(response)); - } else { - __block auto transactionClone = transaction->Clone(); - dispatch_async(self.databaseQueue, ^{ - __block auto response = ledger::type::DBCommandResponse::New(); - rewardsDatabase->RunTransaction(std::move(transactionClone), response.get()); - dispatch_async(dispatch_get_main_queue(), ^{ - callback(std::move(response)); - }); - }); - } + __weak BATBraveLedger* weakSelf = self; + base::PostTaskAndReplyWithResult( + databaseQueue.get(), + FROM_HERE, + base::BindOnce(&RunDBTransactionOnTaskRunner, + base::Passed(std::move(transaction)), + rewardsDatabase), + base::BindOnce(^(ledger::type::DBCommandResponsePtr response) { + if (weakSelf) + callback(std::move(response)); + })); } - (void)pendingContributionSaved:(const ledger::type::Result)result diff --git a/vendor/brave-ios/Ledger/BATBraveLedgerObserver.h b/vendor/brave-ios/Ledger/BATBraveLedgerObserver.h index d9ba5682e29c..25f481b49d4b 100644 --- a/vendor/brave-ios/Ledger/BATBraveLedgerObserver.h +++ b/vendor/brave-ios/Ledger/BATBraveLedgerObserver.h @@ -15,6 +15,7 @@ NS_ASSUME_NONNULL_BEGIN /// Creating a LedgerObserver alone will not respond to any events. Set /// each closure that you wish to watch based on the data being displayed on /// screen +OBJC_EXPORT NS_SWIFT_NAME(LedgerObserver) @interface BATBraveLedgerObserver : NSObject diff --git a/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.h b/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.h index 979ff0be57e8..ef0fc7c7b702 100644 --- a/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.h +++ b/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.h @@ -14,6 +14,7 @@ typedef void (^BATLedgerDatabaseWriteCompletion)(BOOL success); /// /// This class mirrors brave-core's `publisher_info_database.h/cc` file. This file will actually /// likely be removed at a future date when database managment happens in the ledger library +OBJC_EXPORT @interface BATLedgerDatabase : NSObject /// Generates a SQL migration transaction that will move all data in the users diff --git a/vendor/brave-ios/Ledger/Data/DataController.h b/vendor/brave-ios/Ledger/Data/DataController.h index 663576790daf..5f46f5760ddb 100644 --- a/vendor/brave-ios/Ledger/Data/DataController.h +++ b/vendor/brave-ios/Ledger/Data/DataController.h @@ -7,6 +7,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface DataController : NSObject + (BOOL)defaultStoreExists; diff --git a/vendor/brave-ios/Ledger/Data/Model/ActivityInfo.h b/vendor/brave-ios/Ledger/Data/Model/ActivityInfo.h index f3a7ee71ac55..436e65e94f57 100644 --- a/vendor/brave-ios/Ledger/Data/Model/ActivityInfo.h +++ b/vendor/brave-ios/Ledger/Data/Model/ActivityInfo.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface ActivityInfo : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/ContributionInfo.h b/vendor/brave-ios/Ledger/Data/Model/ContributionInfo.h index 41a5090d1bb3..fdf33e102146 100644 --- a/vendor/brave-ios/Ledger/Data/Model/ContributionInfo.h +++ b/vendor/brave-ios/Ledger/Data/Model/ContributionInfo.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface ContributionInfo : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.h b/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.h index 5aa4b02630eb..0c50d3c8f1c0 100644 --- a/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.h +++ b/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface ContributionPublisher : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.h b/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.h index 0171127ac7bc..747a8d61b13c 100644 --- a/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.h +++ b/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface ContributionQueue : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/MediaPublisherInfo.h b/vendor/brave-ios/Ledger/Data/Model/MediaPublisherInfo.h index bdc79156a9fe..ad59a155ef5f 100644 --- a/vendor/brave-ios/Ledger/Data/Model/MediaPublisherInfo.h +++ b/vendor/brave-ios/Ledger/Data/Model/MediaPublisherInfo.h @@ -7,6 +7,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface MediaPublisherInfo : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/PendingContribution.h b/vendor/brave-ios/Ledger/Data/Model/PendingContribution.h index c792aed0e886..fd5b4b8dfba6 100644 --- a/vendor/brave-ios/Ledger/Data/Model/PendingContribution.h +++ b/vendor/brave-ios/Ledger/Data/Model/PendingContribution.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface PendingContribution : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/Promotion.h b/vendor/brave-ios/Ledger/Data/Model/Promotion.h index aeca25dee594..44440284ceed 100644 --- a/vendor/brave-ios/Ledger/Data/Model/Promotion.h +++ b/vendor/brave-ios/Ledger/Data/Model/Promotion.h @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface Promotion : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/PromotionCredentials.h b/vendor/brave-ios/Ledger/Data/Model/PromotionCredentials.h index 99f5f955adb5..1543118742e8 100644 --- a/vendor/brave-ios/Ledger/Data/Model/PromotionCredentials.h +++ b/vendor/brave-ios/Ledger/Data/Model/PromotionCredentials.h @@ -11,6 +11,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface PromotionCredentials : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/PublisherInfo.h b/vendor/brave-ios/Ledger/Data/Model/PublisherInfo.h index 2762d5a93b41..b85ac78b36e5 100644 --- a/vendor/brave-ios/Ledger/Data/Model/PublisherInfo.h +++ b/vendor/brave-ios/Ledger/Data/Model/PublisherInfo.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface PublisherInfo : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/RecurringDonation.h b/vendor/brave-ios/Ledger/Data/Model/RecurringDonation.h index 6f5ff4a488e6..5354df0c3dbf 100644 --- a/vendor/brave-ios/Ledger/Data/Model/RecurringDonation.h +++ b/vendor/brave-ios/Ledger/Data/Model/RecurringDonation.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface RecurringDonation : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/ServerPublisherAmount.h b/vendor/brave-ios/Ledger/Data/Model/ServerPublisherAmount.h index 56b8e3fc9b32..79d6aba6b185 100644 --- a/vendor/brave-ios/Ledger/Data/Model/ServerPublisherAmount.h +++ b/vendor/brave-ios/Ledger/Data/Model/ServerPublisherAmount.h @@ -8,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface ServerPublisherAmount : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/ServerPublisherBanner.h b/vendor/brave-ios/Ledger/Data/Model/ServerPublisherBanner.h index cdd5036b4677..f26b9846c461 100644 --- a/vendor/brave-ios/Ledger/Data/Model/ServerPublisherBanner.h +++ b/vendor/brave-ios/Ledger/Data/Model/ServerPublisherBanner.h @@ -8,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface ServerPublisherBanner : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/ServerPublisherInfo.h b/vendor/brave-ios/Ledger/Data/Model/ServerPublisherInfo.h index 0504428d8bec..c8cfe3d13731 100644 --- a/vendor/brave-ios/Ledger/Data/Model/ServerPublisherInfo.h +++ b/vendor/brave-ios/Ledger/Data/Model/ServerPublisherInfo.h @@ -8,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface ServerPublisherInfo : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/ServerPublisherLink.h b/vendor/brave-ios/Ledger/Data/Model/ServerPublisherLink.h index 38978301c212..8fd98e0ee766 100644 --- a/vendor/brave-ios/Ledger/Data/Model/ServerPublisherLink.h +++ b/vendor/brave-ios/Ledger/Data/Model/ServerPublisherLink.h @@ -8,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface ServerPublisherLink : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Data/Model/UnblindedToken.h b/vendor/brave-ios/Ledger/Data/Model/UnblindedToken.h index 60e9df2a34ce..cede2f6c7251 100644 --- a/vendor/brave-ios/Ledger/Data/Model/UnblindedToken.h +++ b/vendor/brave-ios/Ledger/Data/Model/UnblindedToken.h @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface UnblindedToken : NSManagedObject + (NSFetchRequest *)fetchRequest; diff --git a/vendor/brave-ios/Ledger/Models/BATPromotionSolution.h b/vendor/brave-ios/Ledger/Models/BATPromotionSolution.h index c4f7d169cdc2..6fd26b6356dc 100644 --- a/vendor/brave-ios/Ledger/Models/BATPromotionSolution.h +++ b/vendor/brave-ios/Ledger/Models/BATPromotionSolution.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN /// The solution to claiming a promotion on iOS. Obtain the `nonce` through /// `[BATBraveLedger claimPromotion:completion:]` method, and obtain the /// blob and signature from the users keychain +OBJC_EXPORT NS_SWIFT_NAME(PromotionSolution) @interface BATPromotionSolution : NSObject diff --git a/vendor/brave-ios/Ledger/Models/BATRewardsNotification.h b/vendor/brave-ios/Ledger/Models/BATRewardsNotification.h index 7150059e689f..948fb4ef6377 100644 --- a/vendor/brave-ios/Ledger/Models/BATRewardsNotification.h +++ b/vendor/brave-ios/Ledger/Models/BATRewardsNotification.h @@ -21,6 +21,7 @@ typedef NS_ENUM(NSInteger, BATRewardsNotificationKind) { BATRewardsNotificationKindGeneralLedger // Comes from ledger } NS_SWIFT_NAME(RewardsNotification.Kind); +OBJC_EXPORT NS_SWIFT_NAME(RewardsNotification) @interface BATRewardsNotification : NSObject diff --git a/vendor/brave-ios/Shared/BATCommonOperations.h b/vendor/brave-ios/Shared/BATCommonOperations.h index b0650b1e4f5e..3aa01f721eaa 100644 --- a/vendor/brave-ios/Shared/BATCommonOperations.h +++ b/vendor/brave-ios/Shared/BATCommonOperations.h @@ -17,6 +17,7 @@ typedef void (^BATNetworkCompletionBlock)(const std::string& errorDescription, const std::map& headers); /// A set of common operations that accept and return C++ types +OBJC_EXPORT @interface BATCommonOperations : NSObject - (instancetype)initWithStoragePath:(nullable NSString *)storagePath NS_DESIGNATED_INITIALIZER; diff --git a/vendor/brave-ios/Shared/NSURL+Extensions.h b/vendor/brave-ios/Shared/NSURL+Extensions.h index a0c51432e149..f6042a475a15 100644 --- a/vendor/brave-ios/Shared/NSURL+Extensions.h +++ b/vendor/brave-ios/Shared/NSURL+Extensions.h @@ -6,6 +6,7 @@ NS_ASSUME_NONNULL_BEGIN +OBJC_EXPORT @interface NSURL (Extensions) @property (nonatomic, nullable, readonly) NSString *bat_normalizedHost; diff --git a/vendor/brave-ios/objc-gen/objc-gen/Interface.swift b/vendor/brave-ios/objc-gen/objc-gen/Interface.swift index 20d34574ad20..0bd0e7110605 100644 --- a/vendor/brave-ios/objc-gen/objc-gen/Interface.swift +++ b/vendor/brave-ios/objc-gen/objc-gen/Interface.swift @@ -38,6 +38,7 @@ struct Interface: Hashable, Comparable { /// The generated output of a this @interface var generatedPublicInterface: String { return """ + OBJC_EXPORT NS_SWIFT_NAME(\(name)) @interface \(prefixedName) : NSObject \(properties.map { $0.decleration }.joined(separator: "\n")) diff --git a/vendor/brave-ios/scripts/mojo/objc_templates/interface_declaration.tmpl b/vendor/brave-ios/scripts/mojo/objc_templates/interface_declaration.tmpl index 72acccd33c68..e9a9e4e5e0c0 100644 --- a/vendor/brave-ios/scripts/mojo/objc_templates/interface_declaration.tmpl +++ b/vendor/brave-ios/scripts/mojo/objc_templates/interface_declaration.tmpl @@ -1,4 +1,5 @@ +OBJC_EXPORT NS_SWIFT_NAME({{struct.name}}) @interface {{class_prefix}}{{struct.name}} : NSObject {#- Class properties #} diff --git a/vendor/brave-ios/tests/BUILD.gn b/vendor/brave-ios/tests/BUILD.gn index 551a8ff11ec6..27ddb1b3980b 100644 --- a/vendor/brave-ios/tests/BUILD.gn +++ b/vendor/brave-ios/tests/BUILD.gn @@ -6,11 +6,13 @@ ios_xctest_test("brave_rewards_ios_tests") { check_includes = false deps = [ "//brave/vendor/brave-ios:brave_rewards_ios_framework+link", - "//brave/vendor/bat-native-ledger" + "//brave/vendor/bat-native-ledger", + "//ios/third_party/material_components_ios:material_components_ios+link", ] bundle_deps = [ "//brave/vendor/brave-ios:brave_rewards_ios_framework+bundle", + "//ios/third_party/material_components_ios:material_components_ios+bundle", ] configs += [ "//brave/vendor/brave-ios:internal_config" ] diff --git a/vendor/brave-ios/tests/ads_wrapper_test.mm b/vendor/brave-ios/tests/ads_wrapper_test.mm index 797b945e0ed7..c3a7719632c6 100644 --- a/vendor/brave-ios/tests/ads_wrapper_test.mm +++ b/vendor/brave-ios/tests/ads_wrapper_test.mm @@ -7,6 +7,7 @@ #import #import "BATBraveRewards.h" +#import @interface _MockNotificationHandler : NSObject @property (nonatomic, copy, nullable) void (^showNotification)(BATAdNotification *); @@ -34,6 +35,7 @@ - (void)clearNotificationWithIdentifier:(NSString *)identifier @interface AdsWrapperTest : XCTestCase @property (nonatomic) BATBraveAds *ads; +@property (nonatomic) BraveCoreMain *braveCoreMain; @end @implementation AdsWrapperTest @@ -45,6 +47,9 @@ - (NSString *)stateStoragePath - (void)setUp { + self.braveCoreMain = [[BraveCoreMain alloc] init]; + [self.braveCoreMain scheduleLowPriorityStartupTasks]; + [BATBraveAds setDebug:YES]; const auto path = [self stateStoragePath]; [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; From 23822167e3db63b1ad6a13faac65fcf55e0a00e4 Mon Sep 17 00:00:00 2001 From: Brandon Date: Wed, 2 Dec 2020 00:16:53 -0500 Subject: [PATCH 2/9] Fix signature of function callback. Fixes https://github.com/brave/brave-browser/issues/12997 Fix Linting for Android/Linux --- ios/browser/api/bookmarks/brave_bookmarks_api.h | 5 +++-- ios/browser/api/bookmarks/brave_bookmarks_api.mm | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ios/browser/api/bookmarks/brave_bookmarks_api.h b/ios/browser/api/bookmarks/brave_bookmarks_api.h index f77941d05085..0624154db3a7 100644 --- a/ios/browser/api/bookmarks/brave_bookmarks_api.h +++ b/ios/browser/api/bookmarks/brave_bookmarks_api.h @@ -73,8 +73,9 @@ OBJC_EXPORT @property(nonatomic, readonly) NSUInteger childCount; - (nullable IOSBookmarkNode*)childAtIndex:(NSUInteger)index; -- (NSArray*)nestedChildFoldersFiltered:(BOOL(^)(BookmarkFolder*))included - NS_SWIFT_NAME(nestedChildFolders(where:)); +- (NSArray*)nestedChildFoldersFiltered: + (BOOL(^)(BookmarkFolder*))included + NS_SWIFT_NAME(nestedChildFolders(where:)); - (void)setTitle:(NSString*)title; - (bool)getMetaInfo:(NSString*)key value:(NSString* _Nonnull* _Nullable)value; diff --git a/ios/browser/api/bookmarks/brave_bookmarks_api.mm b/ios/browser/api/bookmarks/brave_bookmarks_api.mm index 86bf848a723d..0308b3141437 100644 --- a/ios/browser/api/bookmarks/brave_bookmarks_api.mm +++ b/ios/browser/api/bookmarks/brave_bookmarks_api.mm @@ -318,7 +318,7 @@ - (IOSBookmarkNode*)parent { - (NSArray*)nestedChildFolders { // Returns a list of ALL nested folders - return [self nestedChildFoldersFiltered:^{ return true; }]; + return [self nestedChildFoldersFiltered:^BOOL(BookmarkFolder*){ return true; }]; } - (NSUInteger)childCount { From a3edbc562b7feefc4c38cff1d51d39b87499930b Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 4 Dec 2020 16:40:04 -0500 Subject: [PATCH 3/9] Fixing BrowserMetrics constantly creating new files taking up 4MB each. Fixes the issue where some users are seeing 5GB worth of files! --- .../chrome/browser/ios_chrome_field_trials.cc | 45 +++ .../ios_chrome_metrics_service_client.mm | 306 ++++++++++++++++++ 2 files changed, 351 insertions(+) create mode 100644 chromium_src/ios/chrome/browser/ios_chrome_field_trials.cc create mode 100644 chromium_src/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm diff --git a/chromium_src/ios/chrome/browser/ios_chrome_field_trials.cc b/chromium_src/ios/chrome/browser/ios_chrome_field_trials.cc new file mode 100644 index 000000000000..d99cef081b62 --- /dev/null +++ b/chromium_src/ios/chrome/browser/ios_chrome_field_trials.cc @@ -0,0 +1,45 @@ +/* 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 "ios/chrome/browser/ios_chrome_field_trials.h" + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "base/task/post_task.h" +#include "base/task/thread_pool.h" +#include "components/metrics/persistent_histograms.h" +#include "ios/chrome/browser/chrome_paths.h" + +namespace { + +void DeleteFileMetrics() { + base::FilePath user_data_dir; + if (base::PathService::Get(ios::DIR_USER_DATA, &user_data_dir)) { + base::FilePath browser_metrics_upload_dir = + user_data_dir.AppendASCII(kBrowserMetricsName); + // When metrics reporting is not enabled, any existing files should be + // deleted in order to preserve user privacy. + base::ThreadPool::PostTask( + FROM_HERE, + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::BindOnce(base::GetDeletePathRecursivelyCallback(), + std::move(browser_metrics_upload_dir))); + } +} + +} // namespace + +void IOSChromeFieldTrials::SetupFieldTrials() { + DeleteFileMetrics(); +} + +void IOSChromeFieldTrials::SetupFeatureControllingFieldTrials( + bool has_seed, + base::FeatureList* feature_list) { + // Add code here to enable field trials that are active at first run. + // See http://crrev/c/1128269 for an example. +} diff --git a/chromium_src/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm b/chromium_src/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm new file mode 100644 index 000000000000..793dd2a7ed9e --- /dev/null +++ b/chromium_src/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm @@ -0,0 +1,306 @@ +/* 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 "ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h" + +#import + +#include +#include +#include + +#include "base/base64.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/check.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" +#include "base/metrics/persistent_histogram_allocator.h" +#include "base/path_service.h" +#include "base/process/process_metrics.h" +#include "base/rand_util.h" +#include "base/strings/string16.h" +#include "base/task/post_task.h" +#include "base/task/thread_pool.h" +#include "base/threading/platform_thread.h" +#include "components/crash/core/common/crash_keys.h" +#include "components/history/core/browser/history_service.h" +#include "components/keyed_service/core/service_access_type.h" +#include "components/metrics/call_stack_profile_metrics_provider.h" +#include "components/metrics/cpu_metrics_provider.h" +#include "components/metrics/demographic_metrics_provider.h" +#include "components/metrics/drive_metrics_provider.h" +#include "components/metrics/field_trials_provider.h" +#include "components/metrics/metrics_log_uploader.h" +#include "components/metrics/metrics_pref_names.h" +#include "components/metrics/metrics_reporting_default_state.h" +#include "components/metrics/metrics_service.h" +#include "components/metrics/metrics_state_manager.h" +#include "components/metrics/net/cellular_logic_helper.h" +#include "components/metrics/net/net_metrics_log_uploader.h" +#include "components/metrics/net/network_metrics_provider.h" +#include "components/metrics/persistent_histograms.h" +#include "components/metrics/stability_metrics_helper.h" +#include "components/metrics/ui/screen_info_metrics_provider.h" +#include "components/metrics/url_constants.h" +#include "components/metrics/version_utils.h" +#include "components/omnibox/browser/omnibox_metrics_provider.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" +#include "components/signin/core/browser/signin_status_metrics_provider.h" +#include "components/sync/driver/sync_service.h" +#include "components/sync_device_info/device_count_metrics_provider.h" +#include "components/ukm/ukm_service.h" +#include "components/variations/variations_associated_data.h" +#include "components/version_info/version_info.h" +#include "google_apis/google_api_keys.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#include "ios/chrome/browser/chrome_paths.h" +#include "ios/chrome/browser/google/google_brand.h" +#include "ios/chrome/browser/history/history_service_factory.h" +#import "ios/chrome/browser/main/browser.h" +#import "ios/chrome/browser/main/browser_list.h" +#import "ios/chrome/browser/main/browser_list_factory.h" +#include "ios/chrome/browser/metrics/chrome_browser_state_client.h" +#import "ios/chrome/browser/metrics/ios_chrome_default_browser_metrics_provider.h" +#include "ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.h" +#include "ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.h" +#include "ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.h" +#include "ios/chrome/browser/sync/device_info_sync_service_factory.h" +#include "ios/chrome/browser/sync/profile_sync_service_factory.h" +#include "ios/chrome/browser/tabs/tab_parenting_global_observer.h" +#include "ios/chrome/browser/translate/translate_ranker_metrics_provider.h" +#import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h" +#include "ios/chrome/browser/web_state_list/web_state_list.h" +#include "ios/chrome/common/channel_info.h" +#include "ios/web/public/thread/web_thread.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +void DeleteFileMetrics() { + base::FilePath user_data_dir; + if (base::PathService::Get(ios::DIR_USER_DATA, &user_data_dir)) { + base::FilePath browser_metrics_upload_dir = + user_data_dir.AppendASCII(kBrowserMetricsName); + // When metrics reporting is not enabled, any existing files should be + // deleted in order to preserve user privacy. + base::ThreadPool::PostTask( + FROM_HERE, + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::BindOnce(base::GetDeletePathRecursivelyCallback(), + std::move(browser_metrics_upload_dir))); + } +} + +} // namespace + +IOSChromeMetricsServiceClient::IOSChromeMetricsServiceClient( + metrics::MetricsStateManager* state_manager) + : metrics_state_manager_(state_manager), + stability_metrics_provider_(nullptr), + weak_ptr_factory_(this) { + DCHECK(thread_checker_.CalledOnValidThread()); + notification_listeners_active_ = RegisterForNotifications(); + metrics_state_manager_ = nullptr; +} + +IOSChromeMetricsServiceClient::~IOSChromeMetricsServiceClient() { + DCHECK(thread_checker_.CalledOnValidThread()); +} + +// static +std::unique_ptr +IOSChromeMetricsServiceClient::Create( + metrics::MetricsStateManager* state_manager) { + // Perform two-phase initialization so that |client->metrics_service_| only + // receives pointers to fully constructed objects. + std::unique_ptr client( + new IOSChromeMetricsServiceClient(state_manager)); + client->Initialize(); + + return client; +} + +// static +void IOSChromeMetricsServiceClient::RegisterPrefs( + PrefRegistrySimple* registry) { + +} + +metrics::MetricsService* IOSChromeMetricsServiceClient::GetMetricsService() { + return nullptr; +} + +ukm::UkmService* IOSChromeMetricsServiceClient::GetUkmService() { + return nullptr; +} + +void IOSChromeMetricsServiceClient::SetMetricsClientId( + const std::string& client_id) { + +} + +int32_t IOSChromeMetricsServiceClient::GetProduct() { + return metrics::ChromeUserMetricsExtension::CHROME; +} + +std::string IOSChromeMetricsServiceClient::GetApplicationLocale() { + return GetApplicationContext()->GetApplicationLocale(); +} + +bool IOSChromeMetricsServiceClient::GetBrand(std::string* brand_code) { + return ios::google_brand::GetBrand(brand_code); +} + +metrics::SystemProfileProto::Channel +IOSChromeMetricsServiceClient::GetChannel() { + return metrics::AsProtobufChannel(::GetChannel()); +} + +std::string IOSChromeMetricsServiceClient::GetVersionString() { + return metrics::GetVersionString(); +} + +void IOSChromeMetricsServiceClient::CollectFinalMetricsForLog( + base::OnceClosure done_callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + + collect_final_metrics_done_callback_ = std::move(done_callback); + CollectFinalHistograms(); +} + +std::unique_ptr +IOSChromeMetricsServiceClient::CreateUploader( + const GURL& server_url, + const GURL& insecure_server_url, + base::StringPiece mime_type, + metrics::MetricsLogUploader::MetricServiceType service_type, + const metrics::MetricsLogUploader::UploadCallback& on_upload_complete) { + return std::make_unique( + GetApplicationContext()->GetSharedURLLoaderFactory(), server_url, + insecure_server_url, mime_type, service_type, on_upload_complete); +} + +base::TimeDelta IOSChromeMetricsServiceClient::GetStandardUploadInterval() { + return metrics::GetUploadInterval(metrics::ShouldUseCellularUploadInterval()); +} + +void IOSChromeMetricsServiceClient::OnRendererProcessCrash() { + stability_metrics_provider_->LogRendererCrash(); +} + +void IOSChromeMetricsServiceClient::WebStateDidStartLoading( + web::WebState* web_state) { + metrics_service_->OnApplicationNotIdle(); +} + +void IOSChromeMetricsServiceClient::WebStateDidStopLoading( + web::WebState* web_state) { + metrics_service_->OnApplicationNotIdle(); +} + +void IOSChromeMetricsServiceClient::Initialize() { + RegisterMetricsServiceProviders(); +} + +void IOSChromeMetricsServiceClient::RegisterMetricsServiceProviders() { + DeleteFileMetrics(); +} + +void IOSChromeMetricsServiceClient::RegisterUKMProviders() { + +} + +void IOSChromeMetricsServiceClient::CollectFinalHistograms() { + DCHECK(thread_checker_.CalledOnValidThread()); +} + +bool IOSChromeMetricsServiceClient::RegisterForNotifications() { + return false; +} + +bool IOSChromeMetricsServiceClient::RegisterForBrowserStateEvents( + ChromeBrowserState* browser_state) { + return false; +} + +void IOSChromeMetricsServiceClient::OnTabParented(web::WebState* web_state) { +} + +void IOSChromeMetricsServiceClient::OnURLOpenedFromOmnibox(OmniboxLog* log) { +} + +// static +metrics::FileMetricsProvider::FilterAction +IOSChromeMetricsServiceClient::FilterBrowserMetricsFiles( + const base::FilePath& path) { + // Do not process the file if it corresponds to the current process id. + base::ProcessId pid; + bool parse_success = base::GlobalHistogramAllocator::ParseFilePath( + path, nullptr, nullptr, &pid); + if (!parse_success) + return metrics::FileMetricsProvider::FILTER_PROCESS_FILE; + if (pid == base::GetCurrentProcId()) + return metrics::FileMetricsProvider::FILTER_ACTIVE_THIS_PID; + // No need to test whether |pid| is a different active process. This isn't + // applicable to iOS because there cannot be two copies of Chrome running. + return metrics::FileMetricsProvider::FILTER_PROCESS_FILE; +} + +metrics::EnableMetricsDefault +IOSChromeMetricsServiceClient::GetMetricsReportingDefaultState() { + return metrics::GetMetricsReportingDefaultState( + GetApplicationContext()->GetLocalState()); +} + +void IOSChromeMetricsServiceClient::OnHistoryDeleted() { + if (ukm_service_) + ukm_service_->Purge(); +} + +void IOSChromeMetricsServiceClient::OnUkmAllowedStateChanged(bool must_purge) { + if (!ukm_service_) + return; + if (must_purge) { + ukm_service_->Purge(); + ukm_service_->ResetClientState(ukm::ResetReason::kOnUkmAllowedStateChanged); + } + // Signal service manager to enable/disable UKM based on new state. + UpdateRunningServices(); +} + +void IOSChromeMetricsServiceClient::OnIncognitoWebStateAdded() { + // Signal service manager to enable/disable UKM based on new state. + UpdateRunningServices(); +} + +void IOSChromeMetricsServiceClient::OnIncognitoWebStateRemoved() { + // Signal service manager to enable/disable UKM based on new state. + UpdateRunningServices(); +} + +bool IOSChromeMetricsServiceClient::IsUkmAllowedForAllProfiles() { + return false; +} + +bool IOSChromeMetricsServiceClient:: + AreNotificationListenersEnabledOnAllProfiles() { + return false; +} + +std::string IOSChromeMetricsServiceClient::GetUploadSigningKey() { + return ""; +} From c339a7f28a1d5dcb9b08805fcc2a5fa2bc4e57bd Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 5 Dec 2020 09:38:38 -0500 Subject: [PATCH 4/9] 1.18.x specific fixes. --- ios/app/BUILD.gn | 1 - ios/app/brave_main_delegate.mm | 12 +++++++++++- vendor/brave-ios/Ads/BATBraveAds.mm | 1 + vendor/brave-ios/BUILD.gn | 1 + 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ios/app/BUILD.gn b/ios/app/BUILD.gn index 4fa82671aecb..c5d8de350ade 100644 --- a/ios/app/BUILD.gn +++ b/ios/app/BUILD.gn @@ -19,7 +19,6 @@ source_set("app") { deps = [ "//base", "//brave/common:pref_names", - "//brave/components/brave_sync:constants", "//brave/ios/browser", "//components/browser_sync", "//components/sync/driver", diff --git a/ios/app/brave_main_delegate.mm b/ios/app/brave_main_delegate.mm index e4ad016c0a51..54d87d0b0266 100644 --- a/ios/app/brave_main_delegate.mm +++ b/ios/app/brave_main_delegate.mm @@ -21,7 +21,17 @@ #endif namespace { -const char kBraveSyncServiceURL[] = BRAVE_SYNC_ENDPOINT; + +#if defined(OFFICIAL_BUILD) +// production +const char kBraveSyncServiceURL[] = "https://sync-v2.brave.com/v2"; +#else +// For local server development "http://localhost:8295/v2 can also be overriden +// by switches::kSyncServiceURL +// dev +const char kBraveSyncServiceURL[] = "https://sync-v2.brave.software/v2"; +#endif + } // namespace BraveMainDelegate::BraveMainDelegate() : brave_sync_service_url_(kBraveSyncServiceURL) { diff --git a/vendor/brave-ios/Ads/BATBraveAds.mm b/vendor/brave-ios/Ads/BATBraveAds.mm index 7297a84a7ebc..4dad0ed0b9c9 100644 --- a/vendor/brave-ios/Ads/BATBraveAds.mm +++ b/vendor/brave-ios/Ads/BATBraveAds.mm @@ -24,6 +24,7 @@ #import "base/strings/sys_string_conversions.h" #include "base/task/post_task.h" #include "base/task_runner_util.h" +#import "brave/base/containers/utils.h" #import "base/base64.h" #import "RewardsLogging.h" diff --git a/vendor/brave-ios/BUILD.gn b/vendor/brave-ios/BUILD.gn index 48f0dc7b7222..5fd04db37589 100644 --- a/vendor/brave-ios/BUILD.gn +++ b/vendor/brave-ios/BUILD.gn @@ -57,6 +57,7 @@ ios_framework_bundle("brave_rewards_ios_framework") { configs += [ "//build/config/compiler:enable_arc" ] deps = [ + "//brave/base:base", "//brave/ios/app", "//brave/vendor/bat-native-ledger", "//brave/vendor/bat-native-ads", From 89633ba9a9df3c57d4bff2a3605257f7e474c717 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 7 Dec 2020 15:48:16 -0500 Subject: [PATCH 5/9] Removed unnecessary headers. --- .../ios_chrome_metrics_service_client.mm | 47 ++----------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/chromium_src/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm b/chromium_src/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm index 793dd2a7ed9e..b393829a1ddb 100644 --- a/chromium_src/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm +++ b/chromium_src/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm @@ -5,80 +5,39 @@ #include "ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h" -#import - #include #include -#include #include "base/base64.h" #include "base/bind.h" #include "base/callback.h" #include "base/check.h" -#include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" + #include "base/metrics/persistent_histogram_allocator.h" #include "base/path_service.h" #include "base/process/process_metrics.h" -#include "base/rand_util.h" #include "base/strings/string16.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" -#include "base/threading/platform_thread.h" -#include "components/crash/core/common/crash_keys.h" -#include "components/history/core/browser/history_service.h" -#include "components/keyed_service/core/service_access_type.h" -#include "components/metrics/call_stack_profile_metrics_provider.h" -#include "components/metrics/cpu_metrics_provider.h" -#include "components/metrics/demographic_metrics_provider.h" -#include "components/metrics/drive_metrics_provider.h" -#include "components/metrics/field_trials_provider.h" #include "components/metrics/metrics_log_uploader.h" -#include "components/metrics/metrics_pref_names.h" -#include "components/metrics/metrics_reporting_default_state.h" #include "components/metrics/metrics_service.h" +#include "components/metrics/metrics_service_client.h" #include "components/metrics/metrics_state_manager.h" #include "components/metrics/net/cellular_logic_helper.h" #include "components/metrics/net/net_metrics_log_uploader.h" -#include "components/metrics/net/network_metrics_provider.h" +#include "components/metrics/metrics_provider.h" #include "components/metrics/persistent_histograms.h" -#include "components/metrics/stability_metrics_helper.h" -#include "components/metrics/ui/screen_info_metrics_provider.h" #include "components/metrics/url_constants.h" #include "components/metrics/version_utils.h" -#include "components/omnibox/browser/omnibox_metrics_provider.h" #include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service.h" -#include "components/signin/core/browser/signin_status_metrics_provider.h" -#include "components/sync/driver/sync_service.h" -#include "components/sync_device_info/device_count_metrics_provider.h" #include "components/ukm/ukm_service.h" -#include "components/variations/variations_associated_data.h" #include "components/version_info/version_info.h" -#include "google_apis/google_api_keys.h" #include "ios/chrome/browser/application_context.h" -#include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" #include "ios/chrome/browser/chrome_paths.h" #include "ios/chrome/browser/google/google_brand.h" -#include "ios/chrome/browser/history/history_service_factory.h" -#import "ios/chrome/browser/main/browser.h" -#import "ios/chrome/browser/main/browser_list.h" -#import "ios/chrome/browser/main/browser_list_factory.h" -#include "ios/chrome/browser/metrics/chrome_browser_state_client.h" -#import "ios/chrome/browser/metrics/ios_chrome_default_browser_metrics_provider.h" #include "ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.h" -#include "ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.h" -#include "ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.h" -#include "ios/chrome/browser/sync/device_info_sync_service_factory.h" -#include "ios/chrome/browser/sync/profile_sync_service_factory.h" -#include "ios/chrome/browser/tabs/tab_parenting_global_observer.h" -#include "ios/chrome/browser/translate/translate_ranker_metrics_provider.h" -#import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h" -#include "ios/chrome/browser/web_state_list/web_state_list.h" #include "ios/chrome/common/channel_info.h" #include "ios/web/public/thread/web_thread.h" #include "services/network/public/cpp/shared_url_loader_factory.h" From c126ef6b6902d740c6f7aa861a0e9ca90ffc6174 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 11 Dec 2020 12:11:14 -0500 Subject: [PATCH 6/9] Fixing missing header. --- chromium_src/ios/chrome/browser/ios_chrome_field_trials.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/chromium_src/ios/chrome/browser/ios_chrome_field_trials.cc b/chromium_src/ios/chrome/browser/ios_chrome_field_trials.cc index d99cef081b62..5596be073864 100644 --- a/chromium_src/ios/chrome/browser/ios_chrome_field_trials.cc +++ b/chromium_src/ios/chrome/browser/ios_chrome_field_trials.cc @@ -5,6 +5,7 @@ #include "ios/chrome/browser/ios_chrome_field_trials.h" +#include "base/feature_list.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/path_service.h" From fdf73a59106c3eaf93c9aa6430f922a8c8cebbf7 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 14 Dec 2020 12:50:42 -0500 Subject: [PATCH 7/9] Merge pull request #7313 from brave/maxk-fix-patches Updated patches with `npm run update_patches` --- patches/ios-chrome-browser-prefs-browser_prefs.mm.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/ios-chrome-browser-prefs-browser_prefs.mm.patch b/patches/ios-chrome-browser-prefs-browser_prefs.mm.patch index 6e83fa563239..98434ba8a5a3 100644 --- a/patches/ios-chrome-browser-prefs-browser_prefs.mm.patch +++ b/patches/ios-chrome-browser-prefs-browser_prefs.mm.patch @@ -3,10 +3,10 @@ index 3a3c235d35be70f98c77659a6233169d85c260e3..da586b7289746f6d24c734aff225108a --- a/ios/chrome/browser/prefs/browser_prefs.mm +++ b/ios/chrome/browser/prefs/browser_prefs.mm @@ -233,6 +233,7 @@ void RegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) { - + registry->RegisterIntegerPref(kPasswordManagerOnboardingState, 0); registry->RegisterBooleanPref(kWasOnboardingFeatureCheckedBefore, false); + BRAVE_REGISTER_BROWSER_STATE_PREFS } - + // This method should be periodically pruned of year+ old migrations. From e1bb8aa7adf619eb689f96070eadf77f498ad238 Mon Sep 17 00:00:00 2001 From: Brian Clifton Date: Thu, 3 Dec 2020 22:41:04 -0700 Subject: [PATCH 8/9] Merge pull request #7337 from brave/fix_gn_check Fix gn_check error on iOS --- ios/browser/api/bookmarks/BUILD.gn | 7 ++++--- ios/browser/api/bookmarks/exporter/BUILD.gn | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ios/browser/api/bookmarks/BUILD.gn b/ios/browser/api/bookmarks/BUILD.gn index 564e3b9e9db9..42b5c71591e1 100644 --- a/ios/browser/api/bookmarks/BUILD.gn +++ b/ios/browser/api/bookmarks/BUILD.gn @@ -19,13 +19,14 @@ source_set("bookmarks") { deps = [ "//base", "//components/bookmarks/browser", - "//components/prefs:prefs", + "//components/prefs", "//components/undo", - "//components/user_prefs:user_prefs", + "//components/user_prefs", "//ios/chrome/browser", "//ios/chrome/browser/bookmarks", "//ios/chrome/browser/browser_state", - "//ios/chrome/browser/ui/bookmarks:bookmarks", + "//ios/chrome/browser/ui/bookmarks", + "//ios/chrome/browser/ui/bookmarks:core", "//ios/chrome/browser/undo", "//ios/web/public/thread", "//net", diff --git a/ios/browser/api/bookmarks/exporter/BUILD.gn b/ios/browser/api/bookmarks/exporter/BUILD.gn index 90422e8e42e4..bbd83f13aa00 100644 --- a/ios/browser/api/bookmarks/exporter/BUILD.gn +++ b/ios/browser/api/bookmarks/exporter/BUILD.gn @@ -20,13 +20,14 @@ source_set("exporter") { deps = [ "//base", + "//brave/ios/browser/api/bookmarks", "//components/bookmarks/browser", "//components/favicon/core", "//components/favicon_base", - "//components/keyed_service/core:core", + "//components/keyed_service/core", "//components/strings:components_strings_grit", "//ios/chrome/browser", - "//ios/chrome/browser/bookmarks:bookmarks", + "//ios/chrome/browser/bookmarks", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/favicon:favicon", "//ios/web/public/thread", From 7d16500be13ef019cd45430e90d6c5adf1d05d77 Mon Sep 17 00:00:00 2001 From: bridiver Date: Tue, 1 Dec 2020 15:49:02 -0700 Subject: [PATCH 9/9] ``` Component //brave/* ERROR at //brave/browser/sync/brave_profile_sync_service_delegate.cc:13:11: Include not allowed. ^----------------------------------------------------- It is not in any dependency of //brave/browser/sync:sync The include file is in the target(s): //chrome/browser:browser which should somehow be reachable. ___________________ ERROR at //brave/browser/sync/brave_profile_sync_service_delegate.cc:14:11: Include not allowed. ^------------------------------------------------- It is not in any dependency of //brave/browser/sync:sync The include file is in the target(s): //chrome/browser:browser which should somehow be reachable. ``` inherited from existing file in a target that already had check_includes = false fix https://github.com/brave/brave-browser/issues/12976 --- browser/sync/BUILD.gn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/browser/sync/BUILD.gn b/browser/sync/BUILD.gn index 90a30e51c146..f11813fb7547 100644 --- a/browser/sync/BUILD.gn +++ b/browser/sync/BUILD.gn @@ -1,4 +1,6 @@ source_set("sync") { + check_includes = false + sources = [ "brave_profile_sync_service_delegate.cc", "brave_profile_sync_service_delegate.h",