diff --git a/DEPS b/DEPS
index 2230ddf..ff0bc0e 100644
--- a/DEPS
+++ b/DEPS
@@ -144,11 +144,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '63fdd0191be0a96bdc642bffbdc08af9dfadef62',
+  'skia_revision': '8c31f2bf7f154e00952da9bdfbe3accc7691aecf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '39c867908d66ff39b240ef7826ebfde9246d3327',
+  'v8_revision': '3ec321d4ceec28228248d2b530719ac180847d3f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -156,11 +156,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '1c16455ea1a50801a33ab7be0b0fd94bbd1f62aa',
+  'angle_revision': 'b243a2a4f27b7ab93b34dd247088afa7c2a10038',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '763b77946e17811b1fed2617434e8886f8a41b42',
+  'swiftshader_revision': '64f2cec30c96dad0ac67cdffe42feda7611fe4ae',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -179,7 +179,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling googletest
   # and whatever else without interference from each other.
-  'googletest_revision': '437e1008c97b6bf595fec85da42c6925babd96b2',
+  'googletest_revision': '6077f444da944d96d311d358d761164261f1cdd0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lighttpd
   # and whatever else without interference from each other.
@@ -279,11 +279,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '6eb681cc54c5d1f50f85ede54f4bb11a58ee86c4',
+  'dawn_revision': '9dbb81f004b65faacbff0e5508bc7b7a40654f2b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': 'd57d3f905ac470ad0b31352907668c22ffb0c0b4',
+  'quiche_revision': '58ac6508f78fd1a1685d9ad23b3fc084ee54e764',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -808,7 +808,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '73df0d84ad47e4916b8259e32b010846fd00261b',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '66c4e85a160b6b01b49a1cafb6776f6012f31e39',
       'condition': 'checkout_linux',
   },
 
@@ -1083,7 +1083,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'cd9f1763c861edfd86d2814e029a34f3ce821e72',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'bb407a27b2e32f89f0e9eeee2bcd0aa9d5cfea3f',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + '51ca718c3adf0ddedacd7df25fe45f67dc5a9ce1',
@@ -1194,7 +1194,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'a7fc7a353fbd5c863363e5e5a34d41dea8e43b4f',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'c182e466c1b0b2d845f5afc15cee84406158ef87',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1362,7 +1362,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6453c2f5604ec8bca15e9e1edc64e979da8f1083',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ea3dddf1d0880e89d84a7e502f65c65993d4169d',
+    Var('webrtc_git') + '/src.git' + '@' + '0be40bf53fc4aa6707636a385e5eaaf01da7c7e4',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1403,7 +1403,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8411465ea3c949b3f13f3076aca61ca4ee996877',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@223c459965a8777dbe34a456508808b65496ad34',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 6249613..14f7bc2 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -17,6 +17,8 @@
     r"^skia[\\/].*",
     r"^third_party[\\/]blink[\\/].*",
     r"^third_party[\\/]breakpad[\\/].*",
+    # sqlite is an imported third party dependency.
+    r"^third_party[\\/]sqlite[\\/].*",
     r"^v8[\\/].*",
     r".*MakeFile$",
     r".+_autogen\.h$",
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 5d93053..516b4ed 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "android_webview/browser/aw_browser_policy_connector.h"
+#include "android_webview/browser/aw_browser_process.h"
 #include "android_webview/browser/aw_content_browser_client.h"
 #include "android_webview/browser/aw_download_manager_delegate.h"
 #include "android_webview/browser/aw_feature_list.h"
@@ -49,7 +50,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/cors_exempt_headers.h"
 #include "content/public/browser/download_request_utils.h"
-#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/ssl_host_state_delegate.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
@@ -63,36 +63,12 @@
 
 namespace android_webview {
 
-namespace prefs {
-
-// String that specifies the Android account type to use for Negotiate
-// authentication.
-const char kAuthAndroidNegotiateAccountType[] =
-    "auth.android_negotiate_account_type";
-
-// Whitelist containing servers for which Integrated Authentication is enabled.
-const char kAuthServerWhitelist[] = "auth.server_whitelist";
-
-}  // namespace prefs
-
 namespace {
 
 const void* const kDownloadManagerDelegateKey = &kDownloadManagerDelegateKey;
 
 AwBrowserContext* g_browser_context = NULL;
 
-std::unique_ptr<net::ProxyConfigServiceAndroid> CreateProxyConfigService() {
-  std::unique_ptr<net::ProxyConfigServiceAndroid> config_service_android =
-      std::make_unique<net::ProxyConfigServiceAndroid>(
-          base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}),
-          base::ThreadTaskRunnerHandle::Get());
-
-  // TODO(csharrison) Architect the wrapper better so we don't need a cast for
-  // android ProxyConfigServices.
-  config_service_android->set_exclude_pac_url(true);
-  return config_service_android;
-}
-
 // Empty method to skip origin security check as DownloadManager will set its
 // own method.
 bool IgnoreOriginSecurityCheck(const GURL& url) {
@@ -186,10 +162,6 @@
                                 false);
   registry->RegisterBooleanPref(autofill::prefs::kAutofillCreditCardEnabled,
                                 false);
-
-  registry->RegisterStringPref(prefs::kAuthServerWhitelist, std::string());
-  registry->RegisterStringPref(prefs::kAuthAndroidNegotiateAccountType,
-                               std::string());
 }
 
 void AwBrowserContext::CreateUserPrefService() {
@@ -212,7 +184,6 @@
           policy::POLICY_LEVEL_MANDATORY));
 
   user_pref_service_ = pref_service_factory.Create(pref_registry);
-  pref_change_registrar_.Init(user_pref_service_.get());
 
   user_prefs::UserPrefs::Set(this, user_pref_service_.get());
 }
@@ -226,15 +197,13 @@
   return supported_schemes;
 }
 
-void AwBrowserContext::PreMainMessageLoopRun(net::NetLog* net_log) {
-  FilePath cache_path = GetCacheDir();
-
+void AwBrowserContext::PreMainMessageLoopRun() {
   CreateUserPrefService();
 
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    // TODO(amalova): Create a new instance for non-default profiles.
     url_request_context_getter_ =
-        new AwURLRequestContextGetter(cache_path, CreateProxyConfigService(),
-                                      user_pref_service_.get(), net_log);
+        AwBrowserProcess::GetInstance()->GetAwURLRequestContext();
   }
 
   scoped_refptr<base::SequencedTaskRunner> db_task_runner =
@@ -250,23 +219,10 @@
 
   EnsureResourceContextInitialized(this);
 
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-    auto auth_pref_callback = base::BindRepeating(
-        &AwBrowserContext::OnAuthPrefsChanged, base::Unretained(this));
-    pref_change_registrar_.Add(prefs::kAuthServerWhitelist, auth_pref_callback);
-    pref_change_registrar_.Add(prefs::kAuthAndroidNegotiateAccountType,
-                               auth_pref_callback);
-  }
-
   content::WebUIControllerFactory::RegisterFactory(
       AwWebUIControllerFactory::GetInstance());
 }
 
-void AwBrowserContext::OnAuthPrefsChanged() {
-  content::GetNetworkService()->ConfigureHttpAuthPrefs(
-      CreateHttpAuthDynamicParams());
-}
-
 void AwBrowserContext::AddVisitedURLs(const std::vector<GURL>& urls) {
   DCHECK(visitedlink_master_);
   visitedlink_master_->AddURLs(urls);
@@ -283,10 +239,6 @@
   return form_database_service_.get();
 }
 
-AwURLRequestContextGetter* AwBrowserContext::GetAwURLRequestContext() {
-  return url_request_context_getter_.get();
-}
-
 autofill::AutocompleteHistoryManager*
 AwBrowserContext::GetAutocompleteHistoryManager() {
   if (!autocomplete_history_manager_) {
@@ -383,7 +335,7 @@
   // content::StoragePartitionImplMap::Create(). This is not fixable
   // until http://crbug.com/159193. Until then, assert that the context
   // has already been allocated and just handle setting the protocol_handlers.
-  DCHECK(url_request_context_getter_.get());
+  DCHECK(url_request_context_getter_);
   url_request_context_getter_->SetHandlersAndInterceptors(
       protocol_handlers, std::move(request_interceptors));
   return url_request_context_getter_.get();
@@ -391,7 +343,7 @@
 
 net::URLRequestContextGetter* AwBrowserContext::CreateMediaRequestContext() {
   DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
-  return url_request_context_getter_.get();
+  return AwBrowserProcess::GetInstance()->GetAwURLRequestContext();
 }
 
 download::InProgressDownloadManager*
@@ -402,19 +354,6 @@
       base::BindRepeating(&content::DownloadRequestUtils::IsURLSafe), nullptr);
 }
 
-network::mojom::HttpAuthDynamicParamsPtr
-AwBrowserContext::CreateHttpAuthDynamicParams() {
-  network::mojom::HttpAuthDynamicParamsPtr auth_dynamic_params =
-      network::mojom::HttpAuthDynamicParams::New();
-
-  auth_dynamic_params->server_whitelist =
-      user_pref_service_->GetString(prefs::kAuthServerWhitelist);
-  auth_dynamic_params->android_negotiate_account_type =
-      user_pref_service_->GetString(prefs::kAuthAndroidNegotiateAccountType);
-
-  return auth_dynamic_params;
-}
-
 void AwBrowserContext::RebuildTable(
     const scoped_refptr<URLEnumerator>& enumerator) {
   // Android WebView rebuilds from WebChromeClient.getVisitedHistory. The client
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index a907818..997dd27 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -15,7 +15,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "components/keyed_service/core/simple_factory_key.h"
-#include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/visitedlink/browser/visitedlink_delegate.h"
 #include "content/public/browser/browser_context.h"
@@ -38,10 +37,6 @@
 class InProgressDownloadManager;
 }
 
-namespace net {
-class NetLog;
-}
-
 namespace policy {
 class BrowserPolicyConnectorBase;
 }
@@ -56,14 +51,6 @@
 class AwQuotaManagerBridge;
 class AwURLRequestContextGetter;
 
-namespace prefs {
-
-// Used for Kerberos authentication.
-extern const char kAuthAndroidNegotiateAccountType[];
-extern const char kAuthServerWhitelist[];
-
-}  // namespace prefs
-
 class AwBrowserContext : public content::BrowserContext,
                          public visitedlink::VisitedLinkDelegate {
  public:
@@ -88,14 +75,13 @@
   static std::vector<std::string> GetAuthSchemes();
 
   // Maps to BrowserMainParts::PreMainMessageLoopRun.
-  void PreMainMessageLoopRun(net::NetLog* net_log);
+  void PreMainMessageLoopRun();
 
   // These methods map to Add methods in visitedlink::VisitedLinkMaster.
   void AddVisitedURLs(const std::vector<GURL>& urls);
 
   AwQuotaManagerBridge* GetQuotaManagerBridge();
   AwFormDatabaseService* GetFormDatabaseService();
-  AwURLRequestContextGetter* GetAwURLRequestContext();
   autofill::AutocompleteHistoryManager* GetAutocompleteHistoryManager();
 
   // content::BrowserContext implementation.
@@ -125,9 +111,6 @@
   // visitedlink::VisitedLinkDelegate implementation.
   void RebuildTable(const scoped_refptr<URLEnumerator>& enumerator) override;
 
-  // Constructs HttpAuthDynamicParams based on |user_pref_service_|.
-  network::mojom::HttpAuthDynamicParamsPtr CreateHttpAuthDynamicParams();
-
   PrefService* GetPrefService() const { return user_pref_service_.get(); }
 
   void SetExtendedReportingAllowed(bool allowed);
@@ -137,7 +120,6 @@
       const base::FilePath& relative_partition_path);
 
  private:
-  void OnAuthPrefsChanged();
   void CreateUserPrefService();
 
   // The file path where data for this context is persisted.
@@ -156,7 +138,6 @@
   std::unique_ptr<policy::BrowserPolicyConnectorBase> browser_policy_connector_;
   std::unique_ptr<AwSSLHostStateDelegate> ssl_host_state_delegate_;
   std::unique_ptr<content::PermissionControllerDelegate> permission_manager_;
-  PrefChangeRegistrar pref_change_registrar_;
 
   SimpleFactoryKey simple_factory_key_;
 
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc
index 724faf9..5fda767 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -119,9 +119,9 @@
 }
 
 void AwBrowserMainParts::PreMainMessageLoopRun() {
+  AwBrowserProcess::GetInstance()->PreMainMessageLoopRun();
   AwBrowserContext* context = browser_client_->InitBrowserContext();
-  context->PreMainMessageLoopRun(browser_client_->GetNonNetworkServiceNetLog());
-  AwBrowserProcess::GetInstance()->InitSafeBrowsing();
+  context->PreMainMessageLoopRun();
   content::RenderFrameHost::AllowInjectingJavaScript();
 }
 
diff --git a/android_webview/browser/aw_browser_policy_connector.cc b/android_webview/browser/aw_browser_policy_connector.cc
index b33c337..0e2feed 100644
--- a/android_webview/browser/aw_browser_policy_connector.cc
+++ b/android_webview/browser/aw_browser_policy_connector.cc
@@ -6,7 +6,7 @@
 
 #include <memory>
 
-#include "android_webview/browser/aw_browser_context.h"
+#include "android_webview/browser/aw_browser_process.h"
 #include "base/bind.h"
 #include "components/policy/core/browser/android/android_combined_policy_provider.h"
 #include "components/policy/core/browser/configuration_policy_handler_list.h"
diff --git a/android_webview/browser/aw_browser_process.cc b/android_webview/browser/aw_browser_process.cc
index 811cc3f..042b08c 100644
--- a/android_webview/browser/aw_browser_process.cc
+++ b/android_webview/browser/aw_browser_process.cc
@@ -5,14 +5,29 @@
 #include "android_webview/browser/aw_browser_process.h"
 
 #include "android_webview/browser/aw_browser_context.h"
+#include "base/base_paths_posix.h"
+#include "base/path_service.h"
 #include "base/task/post_task.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "services/network/public/cpp/features.h"
 
 using content::BrowserThread;
 
 namespace android_webview {
 
+namespace prefs {
+
+// String that specifies the Android account type to use for Negotiate
+// authentication.
+const char kAuthAndroidNegotiateAccountType[] =
+    "auth.android_negotiate_account_type";
+
+// Whitelist containing servers for which Integrated Authentication is enabled.
+const char kAuthServerWhitelist[] = "auth.server_whitelist";
+
+}  // namespace prefs
+
 namespace {
 AwBrowserProcess* g_aw_browser_process = nullptr;
 }  // namespace
@@ -32,6 +47,22 @@
   g_aw_browser_process = nullptr;
 }
 
+void AwBrowserProcess::PreMainMessageLoopRun() {
+  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    pref_change_registrar_.Init(local_state());
+    auto auth_pref_callback = base::BindRepeating(
+        &AwBrowserProcess::OnAuthPrefsChanged, base::Unretained(this));
+    pref_change_registrar_.Add(prefs::kAuthServerWhitelist, auth_pref_callback);
+    pref_change_registrar_.Add(prefs::kAuthAndroidNegotiateAccountType,
+                               auth_pref_callback);
+  }
+
+  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    CreateURLRequestContextGetter();
+  }
+  InitSafeBrowsing();
+}
+
 PrefService* AwBrowserProcess::local_state() {
   if (!local_state_)
     CreateLocalState();
@@ -51,8 +82,8 @@
 }
 
 void AwBrowserProcess::CreateSafeBrowsingUIManager() {
-  safe_browsing_ui_manager_ = new AwSafeBrowsingUIManager(
-      AwBrowserContext::GetDefault()->GetAwURLRequestContext());
+  safe_browsing_ui_manager_ =
+      new AwSafeBrowsingUIManager(AwBrowserProcess::GetAwURLRequestContext());
 }
 
 void AwBrowserProcess::CreateSafeBrowsingWhitelistManager() {
@@ -110,4 +141,60 @@
   return safe_browsing_ui_manager_.get();
 }
 
+// static
+void AwBrowserProcess::RegisterNetworkContextLocalStatePrefs(
+    PrefRegistrySimple* pref_registry) {
+  pref_registry->RegisterStringPref(prefs::kAuthServerWhitelist, std::string());
+  pref_registry->RegisterStringPref(prefs::kAuthAndroidNegotiateAccountType,
+                                    std::string());
+}
+
+network::mojom::HttpAuthDynamicParamsPtr
+AwBrowserProcess::CreateHttpAuthDynamicParams() {
+  network::mojom::HttpAuthDynamicParamsPtr auth_dynamic_params =
+      network::mojom::HttpAuthDynamicParams::New();
+
+  auth_dynamic_params->server_whitelist =
+      local_state()->GetString(prefs::kAuthServerWhitelist);
+  auth_dynamic_params->android_negotiate_account_type =
+      local_state()->GetString(prefs::kAuthAndroidNegotiateAccountType);
+
+  return auth_dynamic_params;
+}
+
+void AwBrowserProcess::OnAuthPrefsChanged() {
+  content::GetNetworkService()->ConfigureHttpAuthPrefs(
+      CreateHttpAuthDynamicParams());
+}
+
+namespace {
+std::unique_ptr<net::ProxyConfigServiceAndroid> CreateProxyConfigService() {
+  std::unique_ptr<net::ProxyConfigServiceAndroid> config_service_android =
+      std::make_unique<net::ProxyConfigServiceAndroid>(
+          base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}),
+          base::ThreadTaskRunnerHandle::Get());
+
+  config_service_android->set_exclude_pac_url(true);
+  return config_service_android;
+}
+}  // namespace
+
+// Default profile reuses global URLRequestGetter
+void AwBrowserProcess::CreateURLRequestContextGetter() {
+  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
+  base::FilePath cache_path;
+  if (!base::PathService::Get(base::DIR_CACHE, &cache_path)) {
+    NOTREACHED() << "Failed to get app cache directory for Android WebView";
+  }
+  cache_path =
+      cache_path.Append(FILE_PATH_LITERAL("org.chromium.android_webview"));
+
+  url_request_context_getter_ = new AwURLRequestContextGetter(
+      cache_path, CreateProxyConfigService(), local_state(), new net::NetLog());
+}
+
+AwURLRequestContextGetter* AwBrowserProcess::GetAwURLRequestContext() {
+  return url_request_context_getter_.get();
+}
+
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_browser_process.h b/android_webview/browser/aw_browser_process.h
index a7aab8a..89eee6a 100644
--- a/android_webview/browser/aw_browser_process.h
+++ b/android_webview/browser/aw_browser_process.h
@@ -7,15 +7,31 @@
 #ifndef ANDROID_WEBVIEW_BROWSER_AW_BROWSER_PROCESS_H_
 #define ANDROID_WEBVIEW_BROWSER_AW_BROWSER_PROCESS_H_
 
+#include "android_webview/browser/aw_browser_context.h"
 #include "android_webview/browser/aw_feature_list_creator.h"
+#include "android_webview/browser/net/aw_url_request_context_getter.h"
 #include "android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h"
 #include "android_webview/browser/safe_browsing/aw_safe_browsing_whitelist_manager.h"
+#include "base/feature_list.h"
+#include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/android/remote_database_manager.h"
 #include "components/safe_browsing/triggers/trigger_manager.h"
+#include "content/public/browser/network_service_instance.h"
+#include "net/log/net_log.h"
+#include "services/network/network_service.h"
+#include "services/network/public/cpp/features.h"
 
 namespace android_webview {
 
+namespace prefs {
+
+// Used for Kerberos authentication.
+extern const char kAuthAndroidNegotiateAccountType[];
+extern const char kAuthServerWhitelist[];
+
+}  // namespace prefs
+
 class AwBrowserProcess {
  public:
   AwBrowserProcess(AwFeatureListCreator* aw_feature_list_creator);
@@ -43,10 +59,23 @@
   // Called on UI and IO threads.
   AwSafeBrowsingUIManager* GetSafeBrowsingUIManager() const;
 
+  static void RegisterNetworkContextLocalStatePrefs(
+      PrefRegistrySimple* pref_registry);
+  // Constructs HttpAuthDynamicParams based on |local_state_|.
+  network::mojom::HttpAuthDynamicParamsPtr CreateHttpAuthDynamicParams();
+
+  AwURLRequestContextGetter* GetAwURLRequestContext();
+
+  void PreMainMessageLoopRun();
+
  private:
   void CreateSafeBrowsingUIManager();
   void CreateSafeBrowsingWhitelistManager();
 
+  void OnAuthPrefsChanged();
+
+  void CreateURLRequestContextGetter();
+
   // If non-null, this object holds a pref store that will be taken by
   // AwBrowserProcess to create the |local_state_|.
   // The AwFeatureListCreator is owned by AwMainDelegate.
@@ -65,11 +94,15 @@
       safe_browsing_db_manager_;
   bool safe_browsing_db_manager_started_ = false;
 
+  PrefChangeRegistrar pref_change_registrar_;
+
   // TODO(amalova): Consider to make WhitelistManager per-profile.
   // Accessed on UI and IO threads.
   std::unique_ptr<AwSafeBrowsingWhitelistManager>
       safe_browsing_whitelist_manager_;
 
+  scoped_refptr<AwURLRequestContextGetter> url_request_context_getter_;
+
   DISALLOW_COPY_AND_ASSIGN(AwBrowserProcess);
 };
 
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index c0271b7..8b65d01 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -96,7 +96,6 @@
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
 #include "net/android/network_library.h"
 #include "net/http/http_util.h"
-#include "net/log/net_log.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_info.h"
 #include "services/network/network_service.h"
@@ -331,9 +330,6 @@
   frame_interfaces_.AddInterface(
       base::BindRepeating(&DummyBindPasswordManagerDriver));
   sniff_file_urls_ = AwSettings::GetAllowSniffingFileUrls();
-
-  if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
-    non_network_service_net_log_.reset(new net::NetLog());
 }
 
 AwContentBrowserClient::~AwContentBrowserClient() {}
@@ -357,12 +353,10 @@
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     return nullptr;
 
-  // There is only one BrowserContext in WebView, so initialize this now as it
-  // depends on the PrefService which is owned by the BrowserContext.
-  auto* aw_context = static_cast<AwBrowserContext*>(context);
   content::GetNetworkService()->ConfigureHttpAuthPrefs(
-      aw_context->CreateHttpAuthDynamicParams());
+      AwBrowserProcess::GetInstance()->CreateHttpAuthDynamicParams());
 
+  auto* aw_context = static_cast<AwBrowserContext*>(context);
   network::mojom::NetworkContextPtr network_context;
   network::mojom::NetworkContextParamsPtr context_params =
       aw_context->GetNetworkContextParams(in_memory, relative_partition_path);
@@ -626,10 +620,6 @@
   AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated();
 }
 
-net::NetLog* AwContentBrowserClient::GetNonNetworkServiceNetLog() {
-  return non_network_service_net_log_.get();
-}
-
 base::FilePath AwContentBrowserClient::GetDefaultDownloadDirectory() {
   // Android WebView does not currently use the Chromium downloads system.
   // Download requests are cancelled immedately when recognized; see
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 05e1ebd..9b34344 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -21,10 +21,6 @@
 class RenderFrameHost;
 }
 
-namespace net {
-class NetLog;
-}
-
 namespace safe_browsing {
 class UrlCheckerDelegate;
 }
@@ -271,9 +267,6 @@
   scoped_refptr<safe_browsing::UrlCheckerDelegate>
   GetSafeBrowsingUrlCheckerDelegate();
 
-  // TODO(eroman): Remove once WebView has switched over to NetworkService.
-  std::unique_ptr<net::NetLog> non_network_service_net_log_;
-
   // Android WebView currently has a single global (non-off-the-record) browser
   // context.
   std::unique_ptr<AwBrowserContext> browser_context_;
diff --git a/android_webview/browser/aw_feature_list_creator.cc b/android_webview/browser/aw_feature_list_creator.cc
index be90a46..6611973e 100644
--- a/android_webview/browser/aw_feature_list_creator.cc
+++ b/android_webview/browser/aw_feature_list_creator.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "android_webview/browser/aw_browser_context.h"
+#include "android_webview/browser/aw_browser_process.h"
 #include "android_webview/browser/aw_metrics_service_client.h"
 #include "android_webview/browser/aw_variations_seed_bridge.h"
 #include "android_webview/browser/net/aw_url_request_context_getter.h"
@@ -79,6 +80,7 @@
 #if BUILDFLAG(ENABLE_MOJO_CDM)
   cdm::MediaDrmStorageImpl::RegisterProfilePrefs(pref_registry.get());
 #endif
+  AwBrowserProcess::RegisterNetworkContextLocalStatePrefs(pref_registry.get());
 
   PrefServiceFactory pref_service_factory;
 
diff --git a/android_webview/browser/aw_proxy_controller.cc b/android_webview/browser/aw_proxy_controller.cc
index ba648c7..02bc7ed 100644
--- a/android_webview/browser/aw_proxy_controller.cc
+++ b/android_webview/browser/aw_proxy_controller.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "android_webview/browser/aw_browser_context.h"
+#include "android_webview/browser/aw_browser_process.h"
 #include "android_webview/browser/net/aw_proxy_config_monitor.h"
 #include "android_webview/browser/net/aw_url_request_context_getter.h"
 #include "android_webview/native_jni/AwProxyController_jni.h"
@@ -81,7 +82,7 @@
                        ScopedJavaGlobalRef<jobject>(env, executor)));
   } else {
     result =
-        AwBrowserContext::GetDefault()
+        AwBrowserProcess::GetInstance()
             ->GetAwURLRequestContext()
             ->SetProxyOverride(
                 proxy_rules, bypass_rules,
@@ -104,7 +105,7 @@
         ScopedJavaGlobalRef<jobject>(env, listener),
         ScopedJavaGlobalRef<jobject>(env, executor)));
   } else {
-    AwBrowserContext::GetDefault()
+    AwBrowserProcess::GetInstance()
         ->GetAwURLRequestContext()
         ->ClearProxyOverride(base::BindOnce(
             &ProxyOverrideChanged, ScopedJavaGlobalRef<jobject>(env, obj),
diff --git a/android_webview/browser/net/aw_url_request_context_getter.cc b/android_webview/browser/net/aw_url_request_context_getter.cc
index 95c7541..d0661d5 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "android_webview/browser/aw_browser_context.h"
+#include "android_webview/browser/aw_browser_process.h"
 #include "android_webview/browser/aw_content_browser_client.h"
 #include "android_webview/browser/aw_feature_list.h"
 #include "android_webview/browser/net/aw_cookie_store_wrapper.h"
diff --git a/android_webview/browser/net/aw_url_request_context_getter_unittest.cc b/android_webview/browser/net/aw_url_request_context_getter_unittest.cc
index 488b31e..6289d94 100644
--- a/android_webview/browser/net/aw_url_request_context_getter_unittest.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "android_webview/browser/aw_browser_context.h"
+#include "android_webview/browser/aw_browser_process.h"
 #include "base/android/jni_android.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
@@ -70,7 +71,8 @@
     ASSERT_TRUE(env_);
 
     pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    AwBrowserContext::RegisterPrefs(pref_service_->registry());
+    AwBrowserProcess::RegisterNetworkContextLocalStatePrefs(
+        pref_service_->registry());
 
     std::unique_ptr<net::ProxyConfigServiceAndroid> config_service_android;
     config_service_android.reset(static_cast<net::ProxyConfigServiceAndroid*>(
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index cda44f2..0a0c0db 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -369,11 +369,6 @@
     "keyboard/virtual_keyboard_container_layout_manager.h",
     "keyboard/virtual_keyboard_controller.cc",
     "keyboard/virtual_keyboard_controller.h",
-    "kiosk_next/kiosk_next_home_controller.cc",
-    "kiosk_next/kiosk_next_home_controller.h",
-    "kiosk_next/kiosk_next_shell_controller_impl.cc",
-    "kiosk_next/kiosk_next_shell_controller_impl.h",
-    "kiosk_next/kiosk_next_shell_observer.h",
     "laser/laser_pointer_controller.cc",
     "laser/laser_pointer_controller.h",
     "laser/laser_pointer_view.cc",
@@ -564,8 +559,6 @@
     "shelf/shelf_background_animator.cc",
     "shelf/shelf_background_animator.h",
     "shelf/shelf_background_animator_observer.h",
-    "shelf/shelf_bezel_event_handler.cc",
-    "shelf/shelf_bezel_event_handler.h",
     "shelf/shelf_bubble.cc",
     "shelf/shelf_bubble.h",
     "shelf/shelf_button.cc",
@@ -1668,10 +1661,6 @@
     "keyboard/keyboard_controller_impl_unittest.cc",
     "keyboard/virtual_keyboard_controller_unittest.cc",
     "keyboard/virtual_keyboard_unittest.cc",
-    "kiosk_next/kiosk_next_shell_test_util.cc",
-    "kiosk_next/kiosk_next_shell_test_util.h",
-    "kiosk_next/mock_kiosk_next_shell_client.cc",
-    "kiosk_next/mock_kiosk_next_shell_client.h",
     "laser/laser_pointer_controller_unittest.cc",
     "laser/laser_segment_utils_unittest.cc",
     "lock_screen_action/lock_screen_action_background_controller_impl_unittest.cc",
diff --git a/ash/accelerators/exit_warning_handler.cc b/ash/accelerators/exit_warning_handler.cc
index a274a69..51dedf1 100644
--- a/ash/accelerators/exit_warning_handler.cc
+++ b/ash/accelerators/exit_warning_handler.cc
@@ -147,7 +147,7 @@
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.accept_events = false;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.delegate = delegate;
   params.bounds = bounds;
   params.name = "ExitWarningWindow";
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc
index 48d756b..22bf7c1 100644
--- a/ash/ash_prefs.cc
+++ b/ash/ash_prefs.cc
@@ -9,7 +9,6 @@
 #include "ash/assistant/assistant_controller.h"
 #include "ash/detachable_base/detachable_base_handler.h"
 #include "ash/display/display_prefs.h"
-#include "ash/kiosk_next/kiosk_next_shell_controller_impl.h"
 #include "ash/login/login_screen_controller.h"
 #include "ash/magnifier/docked_magnifier_controller_impl.h"
 #include "ash/media/media_controller_impl.h"
@@ -39,7 +38,6 @@
   BluetoothPowerController::RegisterProfilePrefs(registry);
   CapsLockNotificationController::RegisterProfilePrefs(registry, for_test);
   DockedMagnifierControllerImpl::RegisterProfilePrefs(registry, for_test);
-  KioskNextShellControllerImpl::RegisterProfilePrefs(registry, for_test);
   LoginScreenController::RegisterProfilePrefs(registry, for_test);
   LogoutButtonTray::RegisterProfilePrefs(registry);
   MediaControllerImpl::RegisterProfilePrefs(registry);
diff --git a/ash/assistant/ui/assistant_container_view.cc b/ash/assistant/ui/assistant_container_view.cc
index ff5688f..8fe6e2e 100644
--- a/ash/assistant/ui/assistant_container_view.cc
+++ b/ash/assistant/ui/assistant_container_view.cc
@@ -312,7 +312,7 @@
     views::Widget* widget) const {
   params->context = delegate_->GetRootWindowForNewWindows();
   params->corner_radius = kCornerRadiusDip;
-  params->keep_on_top = true;
+  params->z_order = ui::ZOrderLevel::kFloatingWindow;
 }
 
 views::ClientView* AssistantContainerView::CreateClientView(
diff --git a/ash/display/shared_display_edge_indicator.cc b/ash/display/shared_display_edge_indicator.cc
index cc3af89..9e79579 100644
--- a/ash/display/shared_display_edge_indicator.cc
+++ b/ash/display/shared_display_edge_indicator.cc
@@ -51,7 +51,7 @@
   params.context = Shell::GetRootWindowControllerWithDisplayId(display.id())
                        ->GetRootWindow();
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   widget->set_focus_on_creation(false);
   widget->Init(params);
   widget->SetVisibilityChangedAnimationsEnabled(false);
diff --git a/ash/display/touch_calibrator_view.cc b/ash/display/touch_calibrator_view.cc
index 015fd99..18613cd5 100644
--- a/ash/display/touch_calibrator_view.cc
+++ b/ash/display/touch_calibrator_view.cc
@@ -87,7 +87,7 @@
   views::Widget::InitParams params;
   params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
   params.name = kWidgetName;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingWindow;
   params.accept_events = true;
   params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
diff --git a/ash/drag_drop/drag_image_view.cc b/ash/drag_drop/drag_image_view.cc
index 8ed7d4b..73e9da6 100644
--- a/ash/drag_drop/drag_image_view.cc
+++ b/ash/drag_drop/drag_image_view.cc
@@ -25,7 +25,6 @@
   Widget::InitParams params;
   params.type = Widget::InitParams::TYPE_TOOLTIP;
   params.name = "DragWidget";
-  params.keep_on_top = true;
   params.accept_events = false;
   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.shadow_type = Widget::InitParams::SHADOW_TYPE_NONE;
@@ -48,7 +47,6 @@
   DCHECK(root_window);
   widget_ = CreateDragWidget(root_window);
   widget_->SetContentsView(this);
-  widget_->SetAlwaysOnTop(true);
 
   // We are owned by the DragDropController.
   set_owned_by_client();
diff --git a/ash/kiosk_next/OWNERS b/ash/kiosk_next/OWNERS
deleted file mode 100644
index 76ae40e..0000000
--- a/ash/kiosk_next/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-agawronska@chromium.org
-brunoad@chromium.org
-ltenorio@chromium.org
-michaelpg@chromium.org
-
-# COMPONENT: UI>Shell>KioskNext
diff --git a/ash/kiosk_next/kiosk_next_home_controller.cc b/ash/kiosk_next/kiosk_next_home_controller.cc
deleted file mode 100644
index 6015dcd8..0000000
--- a/ash/kiosk_next/kiosk_next_home_controller.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2019 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 "ash/kiosk_next/kiosk_next_home_controller.h"
-
-#include <memory>
-
-#include "ash/display/screen_orientation_controller.h"
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/screen_util.h"
-#include "ash/shell.h"
-#include "ash/wm/container_finder.h"
-#include "ash/wm/overview/overview_controller.h"
-#include "ash/wm/toplevel_window_event_handler.h"
-#include "ash/wm/window_util.h"
-#include "ash/wm/wm_event.h"
-#include "base/logging.h"
-#include "ui/aura/window.h"
-#include "ui/base/hit_test.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/display/screen.h"
-#include "ui/events/event_target.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/transform.h"
-
-namespace ash {
-
-KioskNextHomeController::KioskNextHomeController() {
-  display::Screen::GetScreen()->AddObserver(this);
-
-  home_screen_container_ = Shell::GetPrimaryRootWindow()->GetChildById(
-      kShellWindowId_HomeScreenContainer);
-  home_screen_container_->AddObserver(this);
-  if (!home_screen_container_->children().empty()) {
-    DCHECK_EQ(1u, home_screen_container_->children().size());
-    home_screen_window_ = home_screen_container_->children()[0];
-  }
-}
-
-KioskNextHomeController::~KioskNextHomeController() {
-  display::Screen::GetScreen()->RemoveObserver(this);
-
-  if (home_screen_container_)
-    home_screen_container_->RemoveObserver(this);
-}
-
-void KioskNextHomeController::ShowHomeScreenView() {
-  // Nothing to do because the contents of the app window are always shown
-  // on the primary display.
-  // HomeScreenController will show/hide the root home screen window.
-}
-
-aura::Window* KioskNextHomeController::GetHomeScreenWindow() {
-  return home_screen_window_;
-}
-
-void KioskNextHomeController::UpdateYPositionAndOpacityForHomeLauncher(
-    int y_position_in_screen,
-    float opacity,
-    UpdateAnimationSettingsCallback callback) {
-  aura::Window* window = GetHomeScreenWindow();
-  if (!window)
-    return;
-
-  const gfx::Transform translation(1.f, 0.f, 0.f, 1.f, 0.f,
-                                   static_cast<float>(y_position_in_screen));
-  ui::Layer* layer = window->layer();
-  layer->GetAnimator()->StopAnimating();
-  std::unique_ptr<ui::ScopedLayerAnimationSettings> settings;
-  if (!callback.is_null()) {
-    settings = std::make_unique<ui::ScopedLayerAnimationSettings>(
-        layer->GetAnimator());
-    callback.Run(settings.get());
-  }
-  layer->SetOpacity(opacity);
-  layer->SetTransform(translation);
-}
-
-void KioskNextHomeController::UpdateAfterHomeLauncherShown() {}
-
-base::Optional<base::TimeDelta>
-KioskNextHomeController::GetOptionalAnimationDuration() {
-  return base::nullopt;
-}
-
-bool KioskNextHomeController::ShouldShowShelfOnHomeScreen() const {
-  return false;
-}
-
-bool KioskNextHomeController::ShouldShowStatusAreaOnHomeScreen() const {
-  return true;
-}
-
-void KioskNextHomeController::OnDisplayMetricsChanged(
-    const display::Display& display,
-    uint32_t changed_metrics) {
-  aura::Window* window = GetHomeScreenWindow();
-  if (!window)
-    return;
-
-  // Update the window to reflect the display bounds.
-  const gfx::Rect bounds =
-      screen_util::SnapBoundsToDisplayEdge(window->bounds(), window);
-  window->SetBounds(bounds);
-  const wm::WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED);
-  wm::GetWindowState(window)->OnWMEvent(&event);
-}
-
-void KioskNextHomeController::OnWindowAdded(aura::Window* new_window) {
-  DCHECK(!home_screen_window_);
-  DCHECK_EQ(new_window->type(), aura::client::WindowType::WINDOW_TYPE_NORMAL);
-  home_screen_window_ = new_window;
-
-  Shell::Get()->screen_orientation_controller()->LockOrientationForWindow(
-      home_screen_window_, OrientationLockType::kLandscape);
-  Shell::Get()->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem);
-}
-
-void KioskNextHomeController::OnWillRemoveWindow(aura::Window* window) {
-  DCHECK_EQ(home_screen_window_, window);
-  Shell::Get()->RemovePreTargetHandler(this);
-  home_screen_window_ = nullptr;
-}
-
-void KioskNextHomeController::OnWindowDestroying(aura::Window* window) {
-  if (window == home_screen_container_)
-    home_screen_container_ = nullptr;
-}
-
-void KioskNextHomeController::OnGestureEvent(ui::GestureEvent* event) {
-  aura::Window* target = static_cast<aura::Window*>(event->target());
-  int component = wm::GetNonClientComponent(target, event->location());
-
-  aura::Window* new_target =
-      ToplevelWindowEventHandler::GetTargetForClientAreaGesture(event, target);
-
-  if (new_target)
-    target = new_target;
-
-  if (!(target == home_screen_window_ || started_handling_events_))
-    return;
-
-  if (component == HTCLIENT && event->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
-    auto* overview_controller = Shell::Get()->overview_controller();
-    if (!overview_controller->InOverviewSession())
-      overview_controller->StartOverview();
-    started_handling_events_ = true;
-  }
-
-  if (started_handling_events_) {
-    event->SetHandled();
-    event->StopPropagation();
-
-    if (event->type() == ui::EventType::ET_GESTURE_SCROLL_END ||
-        event->type() == ui::EventType::ET_GESTURE_END)
-      started_handling_events_ = false;
-  }
-}
-
-}  // namespace ash
diff --git a/ash/kiosk_next/kiosk_next_home_controller.h b/ash/kiosk_next/kiosk_next_home_controller.h
deleted file mode 100644
index 2c24d7f..0000000
--- a/ash/kiosk_next/kiosk_next_home_controller.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef ASH_KIOSK_NEXT_KIOSK_NEXT_HOME_CONTROLLER_H_
-#define ASH_KIOSK_NEXT_KIOSK_NEXT_HOME_CONTROLLER_H_
-
-#include "ash/ash_export.h"
-#include "ash/home_screen/home_screen_delegate.h"
-#include "base/macros.h"
-#include "ui/aura/window_observer.h"
-#include "ui/display/display_observer.h"
-#include "ui/events/event_handler.h"
-
-namespace ui {
-class GestureEvent;
-}
-
-namespace ash {
-
-// KioskNextHomeController manages the Home window for the Kiosk Next shell.
-// TODO(michaelpg): Show a slide-down animation when opening Overview.
-// TODO(michaelpg): Suppress tap events in the Kiosk Next Home window when a
-// gesture event triggers Overview this way.
-class ASH_EXPORT KioskNextHomeController : public HomeScreenDelegate,
-                                           public display::DisplayObserver,
-                                           public aura::WindowObserver,
-                                           public ui::EventHandler {
- public:
-  KioskNextHomeController();
-  ~KioskNextHomeController() override;
-
-  // HomeScreenDelegate:
-  void ShowHomeScreenView() override;
-  aura::Window* GetHomeScreenWindow() override;
-  void UpdateYPositionAndOpacityForHomeLauncher(
-      int y_position_in_screen,
-      float opacity,
-      UpdateAnimationSettingsCallback callback) override;
-  void UpdateAfterHomeLauncherShown() override;
-  base::Optional<base::TimeDelta> GetOptionalAnimationDuration() override;
-  bool ShouldShowShelfOnHomeScreen() const override;
-  bool ShouldShowStatusAreaOnHomeScreen() const override;
-
-  // display::DisplayObserver:
-  void OnDisplayMetricsChanged(const display::Display& display,
-                               uint32_t changed_metrics) override;
-
-  // aura::WindowObserver:
-  void OnWindowAdded(aura::Window* new_window) override;
-  void OnWillRemoveWindow(aura::Window* window) override;
-  void OnWindowDestroying(aura::Window* window) override;
-
-  // ui::EventHandler:
-  void OnGestureEvent(ui::GestureEvent* event) override;
-
- private:
-  bool started_handling_events_ = false;
-  aura::Window* home_screen_container_ = nullptr;
-  aura::Window* home_screen_window_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(KioskNextHomeController);
-};
-
-}  // namespace ash
-
-#endif  // ASH_KIOSK_NEXT_KIOSK_NEXT_HOME_CONTROLLER_H_
diff --git a/ash/kiosk_next/kiosk_next_shell_controller_impl.cc b/ash/kiosk_next/kiosk_next_shell_controller_impl.cc
deleted file mode 100644
index 27e4e63..0000000
--- a/ash/kiosk_next/kiosk_next_shell_controller_impl.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2018 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 "ash/kiosk_next/kiosk_next_shell_controller_impl.h"
-
-#include <memory>
-#include <utility>
-
-#include "ash/home_screen/home_screen_controller.h"
-#include "ash/kiosk_next/kiosk_next_home_controller.h"
-#include "ash/kiosk_next/kiosk_next_shell_observer.h"
-#include "ash/public/cpp/ash_features.h"
-#include "ash/public/cpp/ash_pref_names.h"
-#include "ash/public/cpp/shelf_model.h"
-#include "ash/session/session_controller_impl.h"
-#include "ash/shell.h"
-#include "ash/strings/grit/ash_strings.h"
-#include "base/metrics/histogram_macros.h"
-#include "chromeos/strings/grit/chromeos_strings.h"
-#include "components/account_id/account_id.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace ash {
-
-KioskNextShellControllerImpl::KioskNextShellControllerImpl() = default;
-
-KioskNextShellControllerImpl::~KioskNextShellControllerImpl() = default;
-
-// static
-void KioskNextShellControllerImpl::RegisterProfilePrefs(
-    PrefRegistrySimple* registry,
-    bool for_test) {
-  if (for_test) {
-    registry->RegisterBooleanPref(prefs::kKioskNextShellEnabled, false,
-                                  PrefRegistry::PUBLIC);
-    return;
-  }
-}
-
-void KioskNextShellControllerImpl::SetClientAndLaunchSession(
-    KioskNextShellClient* client) {
-  DCHECK_NE(!!client, !!client_);
-  client_ = client;
-  LaunchKioskNextShellIfEnabled();
-}
-
-bool KioskNextShellControllerImpl::IsEnabled() {
-  return kiosk_next_enabled_;
-}
-
-void KioskNextShellControllerImpl::AddObserver(
-    KioskNextShellObserver* observer) {
-  observer_list_.AddObserver(observer);
-}
-
-void KioskNextShellControllerImpl::RemoveObserver(
-    KioskNextShellObserver* observer) {
-  observer_list_.RemoveObserver(observer);
-}
-
-void KioskNextShellControllerImpl::OnActiveUserPrefServiceChanged(
-    PrefService* pref_service) {
-  LaunchKioskNextShellIfEnabled();
-}
-
-void KioskNextShellControllerImpl::LaunchKioskNextShellIfEnabled() {
-  SessionControllerImpl* session_controller =
-      Shell::Get()->session_controller();
-  PrefService* pref_service = session_controller->GetPrimaryUserPrefService();
-  if (!pref_service)
-    return;
-
-  if (!client_)
-    return;
-
-  bool prev_kiosk_next_enabled = kiosk_next_enabled_;
-  kiosk_next_enabled_ =
-      base::FeatureList::IsEnabled(features::kKioskNextShell) &&
-      pref_service->GetBoolean(prefs::kKioskNextShellEnabled);
-  if (!kiosk_next_enabled_ || prev_kiosk_next_enabled)
-    return;
-
-  // Replace the AppListController with a KioskNextHomeController.
-  kiosk_next_home_controller_ = std::make_unique<KioskNextHomeController>();
-  Shell::Get()->home_screen_controller()->SetDelegate(
-      kiosk_next_home_controller_.get());
-  Shell::Get()->RemoveAppListController();
-
-  client_->LaunchKioskNextShell(
-      session_controller->GetPrimaryUserSession()->user_info.account_id);
-  UMA_HISTOGRAM_BOOLEAN("KioskNextShell.Launched", true);
-
-  // Since the kiosk next shelf only has navigation buttons (back and home),
-  // its shelf model for apps is empty.
-  shelf_model_ = std::make_unique<ShelfModel>();
-
-  // Notify observers that KioskNextShell has been enabled.
-  for (KioskNextShellObserver& observer : observer_list_) {
-    observer.OnKioskNextEnabled();
-  }
-}
-
-}  // namespace ash
diff --git a/ash/kiosk_next/kiosk_next_shell_controller_impl.h b/ash/kiosk_next/kiosk_next_shell_controller_impl.h
deleted file mode 100644
index acb5c9b..0000000
--- a/ash/kiosk_next/kiosk_next_shell_controller_impl.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef ASH_KIOSK_NEXT_KIOSK_NEXT_SHELL_CONTROLLER_IMPL_H_
-#define ASH_KIOSK_NEXT_KIOSK_NEXT_SHELL_CONTROLLER_IMPL_H_
-
-#include <memory>
-
-#include "ash/ash_export.h"
-#include "ash/kiosk_next/kiosk_next_shell_observer.h"
-#include "ash/public/cpp/kiosk_next_shell.h"
-#include "ash/session/session_observer.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-
-class PrefRegistrySimple;
-
-namespace ash {
-
-class KioskNextHomeController;
-class ShelfModel;
-
-// KioskNextShellControllerImpl allows an ash consumer to manage a Kiosk Next
-// session. During this session most system functions are disabled and we launch
-// a specific app (Kiosk Next Home) that takes the whole screen.
-class ASH_EXPORT KioskNextShellControllerImpl : public KioskNextShellController,
-                                                public SessionObserver {
- public:
-  KioskNextShellControllerImpl();
-  ~KioskNextShellControllerImpl() override;
-
-  // Register prefs related to the Kiosk Next Shell.
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test);
-
-  // KioskNextShellController:
-  void SetClientAndLaunchSession(KioskNextShellClient* client) override;
-
-  // Returns if the Kiosk Next Shell is enabled for the current user. If there's
-  // no signed-in user, this returns false.
-  bool IsEnabled();
-
-  void AddObserver(KioskNextShellObserver* observer);
-  void RemoveObserver(KioskNextShellObserver* observer);
-
-  // SessionObserver:
-  void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
-
-  ShelfModel* shelf_model() { return shelf_model_.get(); }
-
- private:
-  // Launches Kiosk Next if the pref is enabled and the KioskNextShellClient is
-  // available.
-  void LaunchKioskNextShellIfEnabled();
-
-  KioskNextShellClient* client_ = nullptr;
-
-  base::ObserverList<KioskNextShellObserver> observer_list_;
-  ScopedSessionObserver session_observer_{this};
-  bool kiosk_next_enabled_ = false;
-
-  // Controls the KioskNext home screen when the Kiosk Next Shell is enabled.
-  std::unique_ptr<KioskNextHomeController> kiosk_next_home_controller_;
-
-  // When KioskNextShell is enabled, only the home button and back button are
-  // made visible on the Shelf. KioskNextShellControllerImpl therefore hosts its
-  // own ShelfModel to control the entries visible on the shelf.
-  std::unique_ptr<ShelfModel> shelf_model_;
-
-  DISALLOW_COPY_AND_ASSIGN(KioskNextShellControllerImpl);
-};
-
-}  // namespace ash
-
-#endif  // ASH_KIOSK_NEXT_KIOSK_NEXT_SHELL_CONTROLLER_IMPL_H_
diff --git a/ash/kiosk_next/kiosk_next_shell_observer.h b/ash/kiosk_next/kiosk_next_shell_observer.h
deleted file mode 100644
index 9c57e86..0000000
--- a/ash/kiosk_next/kiosk_next_shell_observer.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef ASH_KIOSK_NEXT_KIOSK_NEXT_SHELL_OBSERVER_H_
-#define ASH_KIOSK_NEXT_KIOSK_NEXT_SHELL_OBSERVER_H_
-
-#include "ash/ash_export.h"
-#include "base/observer_list_types.h"
-
-namespace ash {
-
-class ASH_EXPORT KioskNextShellObserver : public base::CheckedObserver {
- public:
-  // This method is only called once when KioskNextShell is enabled.
-  virtual void OnKioskNextEnabled() {}
-};
-
-}  // namespace ash
-
-#endif  // ASH_KIOSK_NEXT_KIOSK_NEXT_SHELL_OBSERVER_H_
diff --git a/ash/kiosk_next/kiosk_next_shell_test_util.cc b/ash/kiosk_next/kiosk_next_shell_test_util.cc
deleted file mode 100644
index eacbae8..0000000
--- a/ash/kiosk_next/kiosk_next_shell_test_util.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2019 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 "ash/kiosk_next/kiosk_next_shell_test_util.h"
-
-#include "ash/public/cpp/ash_pref_names.h"
-#include "ash/session/session_controller_impl.h"
-#include "ash/session/test_session_controller_client.h"
-#include "ash/shell.h"
-#include "components/prefs/pref_service.h"
-
-namespace ash {
-namespace {
-
-const char kTestUserEmail[] = "primary_user1@test.com";
-
-}  // namespace
-
-void LogInKioskNextUser(
-    TestSessionControllerClient* session_controller_client) {
-  // Create session for user.
-  session_controller_client->AddUserSession(
-      kTestUserEmail, user_manager::USER_TYPE_REGULAR,
-      true /* enable_settings */, true /* provide_pref_service */);
-
-  // Set the user's KioskNextShell preference.
-  PrefService* pref_service =
-      Shell::Get()->session_controller()->GetUserPrefServiceForUser(
-          AccountId::FromUserEmail(kTestUserEmail));
-  pref_service->Set(prefs::kKioskNextShellEnabled, base::Value(true));
-
-  // Start the session after setting the pref.
-  session_controller_client->SwitchActiveUser(
-      AccountId::FromUserEmail(kTestUserEmail));
-  session_controller_client->SetSessionState(
-      session_manager::SessionState::ACTIVE);
-}
-
-}  // namespace ash
diff --git a/ash/kiosk_next/kiosk_next_shell_test_util.h b/ash/kiosk_next/kiosk_next_shell_test_util.h
deleted file mode 100644
index ee7c95a..0000000
--- a/ash/kiosk_next/kiosk_next_shell_test_util.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef ASH_KIOSK_NEXT_KIOSK_NEXT_SHELL_TEST_UTIL_H_
-#define ASH_KIOSK_NEXT_KIOSK_NEXT_SHELL_TEST_UTIL_H_
-
-namespace ash {
-
-class TestSessionControllerClient;
-
-// Logs in a user with Kiosk Next enabled.
-void LogInKioskNextUser(TestSessionControllerClient* session_controller_client);
-
-}  // namespace ash
-
-#endif  // ASH_KIOSK_NEXT_KIOSK_NEXT_SHELL_TEST_UTIL_H_
diff --git a/ash/kiosk_next/mock_kiosk_next_shell_client.cc b/ash/kiosk_next/mock_kiosk_next_shell_client.cc
deleted file mode 100644
index f9f78b7..0000000
--- a/ash/kiosk_next/mock_kiosk_next_shell_client.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 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 "ash/kiosk_next/mock_kiosk_next_shell_client.h"
-
-namespace ash {
-
-MockKioskNextShellClient::MockKioskNextShellClient() {
-  KioskNextShellController::Get()->SetClientAndLaunchSession(this);
-}
-
-MockKioskNextShellClient::~MockKioskNextShellClient() {
-  KioskNextShellController::Get()->SetClientAndLaunchSession(nullptr);
-}
-
-}  // namespace ash
diff --git a/ash/kiosk_next/mock_kiosk_next_shell_client.h b/ash/kiosk_next/mock_kiosk_next_shell_client.h
deleted file mode 100644
index 9830ac0..0000000
--- a/ash/kiosk_next/mock_kiosk_next_shell_client.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef ASH_KIOSK_NEXT_MOCK_KIOSK_NEXT_SHELL_CLIENT_H_
-#define ASH_KIOSK_NEXT_MOCK_KIOSK_NEXT_SHELL_CLIENT_H_
-
-#include "ash/public/cpp/kiosk_next_shell.h"
-#include "base/macros.h"
-#include "components/account_id/account_id.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace ash {
-
-class MockKioskNextShellClient : public KioskNextShellClient {
- public:
-  MockKioskNextShellClient();
-  ~MockKioskNextShellClient() override;
-
-  // KioskNextShellClient:
-  MOCK_METHOD1(LaunchKioskNextShell, void(const AccountId& account_id));
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockKioskNextShellClient);
-};
-
-}  // namespace ash
-
-#endif  // ASH_KIOSK_NEXT_MOCK_KIOSK_NEXT_SHELL_CLIENT_H_
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index c4f4d10..92f715d8 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -111,8 +111,6 @@
     "keyboard_shortcut_viewer.h",
     "kiosk_app_menu.cc",
     "kiosk_app_menu.h",
-    "kiosk_next_shell.cc",
-    "kiosk_next_shell.h",
     "locale_update_controller.cc",
     "locale_update_controller.h",
     "lock_screen_widget_factory.cc",
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index bb76172..4e2777d 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -115,14 +115,6 @@
 // regardless of the state of a11y features.
 const char kShouldAlwaysShowAccessibilityMenu[] = "settings.a11y.enable_menu";
 
-// A boolean pref that stores whether the user is eligible to start the Kiosk
-// Next shell.
-const char kKioskNextShellEligible[] = "ash.kiosk_next_shell.eligible";
-
-// A boolean pref that stores whether the Kiosk Next Shell is enabled. When it
-// is, we start it after sign in.
-const char kKioskNextShellEnabled[] = "ash.kiosk_next_shell.enabled";
-
 // A boolean pref storing the enabled status of the Docked Magnifier feature.
 const char kDockedMagnifierEnabled[] = "ash.docked_magnifier.enabled";
 // A double pref storing the scale value of the Docked Magnifier feature by
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index e26744c..0a837ff 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -45,9 +45,6 @@
 ASH_PUBLIC_EXPORT extern const char kAccessibilityDictationEnabled[];
 ASH_PUBLIC_EXPORT extern const char kShouldAlwaysShowAccessibilityMenu[];
 
-ASH_PUBLIC_EXPORT extern const char kKioskNextShellEligible[];
-ASH_PUBLIC_EXPORT extern const char kKioskNextShellEnabled[];
-
 ASH_PUBLIC_EXPORT extern const char kDockedMagnifierEnabled[];
 ASH_PUBLIC_EXPORT extern const char kDockedMagnifierScale[];
 ASH_PUBLIC_EXPORT extern const char
diff --git a/ash/public/cpp/kiosk_next_shell.cc b/ash/public/cpp/kiosk_next_shell.cc
deleted file mode 100644
index cb9d503f..0000000
--- a/ash/public/cpp/kiosk_next_shell.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2019 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 "ash/public/cpp/kiosk_next_shell.h"
-
-#include "base/logging.h"
-
-namespace ash {
-
-namespace {
-KioskNextShellController* g_instance = nullptr;
-}
-
-// static
-KioskNextShellController* KioskNextShellController::Get() {
-  return g_instance;
-}
-
-KioskNextShellController::KioskNextShellController() {
-  DCHECK_EQ(nullptr, g_instance);
-  g_instance = this;
-}
-
-KioskNextShellController::~KioskNextShellController() {
-  DCHECK_EQ(this, g_instance);
-  g_instance = nullptr;
-}
-
-}  // namespace ash
diff --git a/ash/public/cpp/kiosk_next_shell.h b/ash/public/cpp/kiosk_next_shell.h
deleted file mode 100644
index 7011e6c..0000000
--- a/ash/public/cpp/kiosk_next_shell.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef ASH_PUBLIC_CPP_KIOSK_NEXT_SHELL_H_
-#define ASH_PUBLIC_CPP_KIOSK_NEXT_SHELL_H_
-
-#include "ash/public/cpp/ash_public_export.h"
-
-class AccountId;
-
-namespace ash {
-
-// Performs browser-side functionality for Kiosk Next, e.g. launching the
-// KioskNextShell.
-class ASH_PUBLIC_EXPORT KioskNextShellClient {
- public:
-  // Launch the Kiosk Next Shell for the user identified by |account_id|.
-  virtual void LaunchKioskNextShell(const AccountId& account_id) = 0;
-
- protected:
-  virtual ~KioskNextShellClient() = default;
-};
-
-// Interface that allows Chrome to notify Ash when the KioskNextShellClient is
-// ready.
-class ASH_PUBLIC_EXPORT KioskNextShellController {
- public:
-  static KioskNextShellController* Get();
-
-  // Registers the client, and if non-null, launches the Kiosk Next Shell
-  // session.
-  virtual void SetClientAndLaunchSession(KioskNextShellClient* client) = 0;
-
- protected:
-  KioskNextShellController();
-  virtual ~KioskNextShellController();
-};
-
-}  // namespace ash
-
-#endif  // ASH_PUBLIC_CPP_KIOSK_NEXT_SHELL_H_
diff --git a/ash/shelf/overflow_bubble_view.cc b/ash/shelf/overflow_bubble_view.cc
index d7a9712..10e343e 100644
--- a/ash/shelf/overflow_bubble_view.cc
+++ b/ash/shelf/overflow_bubble_view.cc
@@ -31,7 +31,7 @@
 namespace ash {
 namespace {
 
-// Padding between the end of the shelf in overview mode and the arrow button
+// Padding between the end of the shelf in overflow mode and the arrow button
 // (if any).
 constexpr int kDistanceToArrowButton = kShelfButtonSpacing;
 
@@ -41,6 +41,10 @@
 // Sum of the shelf button size and the gap between shelf buttons.
 constexpr int kUnit = kShelfButtonSize + kShelfButtonSpacing;
 
+// Decides whether the current first visible shelf icon of the overflow shelf
+// should be hidden or fully shown when gesture scroll ends.
+constexpr int kGestureDragThreshold = kShelfButtonSize / 2;
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -256,10 +260,31 @@
 bool OverflowBubbleView::ProcessGestureEvent(const ui::GestureEvent& event) {
   // Handle scroll-related events, but don't do anything special for begin and
   // end.
-  if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN ||
-      event.type() == ui::ET_GESTURE_SCROLL_END) {
+  if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN) {
     return true;
   }
+
+  // Make sure that no visible shelf button is partially shown after gestures.
+  if (event.type() == ui::ET_GESTURE_END ||
+      event.type() == ui::ET_GESTURE_SCROLL_END) {
+    int current_scroll_distance = shelf_->IsHorizontalAlignment()
+                                      ? scroll_offset_.x()
+                                      : scroll_offset_.y();
+    const int residue = current_scroll_distance % kUnit;
+
+    // if it does not need to adjust the location of the shelf view,
+    // return early.
+    if (current_scroll_distance == CalculateScrollUpperBound() || residue == 0)
+      return true;
+
+    int offset = residue > kGestureDragThreshold ? kUnit - residue : -residue;
+    if (shelf_->IsHorizontalAlignment())
+      ScrollByXOffset(offset, /*animate=*/true);
+    else
+      ScrollByYOffset(offset, /*animate=*/true);
+    return true;
+  }
+
   if (event.type() != ui::ET_GESTURE_SCROLL_UPDATE)
     return false;
 
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index 0324a08..245fff7 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -13,7 +13,6 @@
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
-#include "ash/shelf/shelf_bezel_event_handler.h"
 #include "ash/shelf/shelf_controller.h"
 #include "ash/shelf/shelf_focus_cycler.h"
 #include "ash/shelf/shelf_layout_manager.h"
@@ -34,8 +33,7 @@
 // Forwards mouse and gesture events to ShelfLayoutManager for auto-hide.
 class Shelf::AutoHideEventHandler : public ui::EventHandler {
  public:
-  explicit AutoHideEventHandler(ShelfLayoutManager* shelf_layout_manager)
-      : shelf_layout_manager_(shelf_layout_manager) {
+  explicit AutoHideEventHandler(Shelf* shelf) : shelf_(shelf) {
     Shell::Get()->AddPreTargetHandler(this);
   }
   ~AutoHideEventHandler() override {
@@ -44,16 +42,36 @@
 
   // ui::EventHandler:
   void OnMouseEvent(ui::MouseEvent* event) override {
-    shelf_layout_manager_->UpdateAutoHideForMouseEvent(
+    shelf_->shelf_layout_manager()->UpdateAutoHideForMouseEvent(
         event, static_cast<aura::Window*>(event->target()));
   }
   void OnGestureEvent(ui::GestureEvent* event) override {
-    shelf_layout_manager_->ProcessGestureEventOfAutoHideShelf(
+    shelf_->shelf_layout_manager()->ProcessGestureEventOfAutoHideShelf(
         event, static_cast<aura::Window*>(event->target()));
   }
+  void OnTouchEvent(ui::TouchEvent* event) override {
+    if (shelf_->auto_hide_behavior() != SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS)
+      return;
+
+    // The event target should be the shelf widget.
+    aura::Window* target = static_cast<aura::Window*>(event->target());
+    if (target != Shelf::ForWindow(target)->shelf_widget()->GetNativeView())
+      return;
+
+    // The touch-pressing event may hide the shelf. Lock the shelf's auto hide
+    // state to give the shelf a chance to handle the touch event before it
+    // being hidden.
+    ShelfLayoutManager* shelf_layout_manager = shelf_->shelf_layout_manager();
+    if (event->type() == ui::ET_TOUCH_PRESSED && shelf_->IsVisible()) {
+      shelf_layout_manager->LockAutoHideState(true);
+    } else if (event->type() == ui::ET_TOUCH_RELEASED ||
+               event->type() == ui::ET_TOUCH_CANCELLED) {
+      shelf_layout_manager->LockAutoHideState(false);
+    }
+  }
 
  private:
-  ShelfLayoutManager* shelf_layout_manager_;
+  Shelf* shelf_;
   DISALLOW_COPY_AND_ASSIGN(AutoHideEventHandler);
 };
 
@@ -61,7 +79,6 @@
 
 Shelf::Shelf()
     : shelf_locking_manager_(this),
-      bezel_event_handler_(std::make_unique<ShelfBezelEventHandler>(this)),
       shelf_focus_cycler_(std::make_unique<ShelfFocusCycler>(this)) {}
 
 Shelf::~Shelf() = default;
@@ -347,7 +364,6 @@
 void Shelf::WillDeleteShelfLayoutManager() {
   // Clear event handlers that might forward events to the destroyed instance.
   auto_hide_event_handler_.reset();
-  bezel_event_handler_.reset();
 
   DCHECK(shelf_layout_manager_);
   shelf_layout_manager_->RemoveObserver(this);
@@ -360,8 +376,7 @@
   if (new_state != SHELF_AUTO_HIDE) {
     auto_hide_event_handler_.reset();
   } else if (!auto_hide_event_handler_) {
-    auto_hide_event_handler_ =
-        std::make_unique<AutoHideEventHandler>(shelf_layout_manager());
+    auto_hide_event_handler_ = std::make_unique<AutoHideEventHandler>(this);
   }
 }
 
diff --git a/ash/shelf/shelf.h b/ash/shelf/shelf.h
index 9a37ed1..394b8ea 100644
--- a/ash/shelf/shelf.h
+++ b/ash/shelf/shelf.h
@@ -30,7 +30,6 @@
 namespace ash {
 
 enum class AnimationChangeType;
-class ShelfBezelEventHandler;
 class ShelfFocusCycler;
 class ShelfLayoutManager;
 class ShelfLayoutManagerTest;
@@ -221,9 +220,6 @@
   // Forwards mouse and gesture events to ShelfLayoutManager for auto-hide.
   std::unique_ptr<AutoHideEventHandler> auto_hide_event_handler_;
 
-  // Forwards touch gestures on a bezel sensor to the shelf.
-  std::unique_ptr<ShelfBezelEventHandler> bezel_event_handler_;
-
   // Hands focus off to different parts of the shelf.
   std::unique_ptr<ShelfFocusCycler> shelf_focus_cycler_;
 
diff --git a/ash/shelf/shelf_bezel_event_handler.cc b/ash/shelf/shelf_bezel_event_handler.cc
deleted file mode 100644
index 1531645..0000000
--- a/ash/shelf/shelf_bezel_event_handler.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2013 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 "ash/shelf/shelf_bezel_event_handler.h"
-
-#include "ash/shelf/shelf.h"
-#include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_widget.h"
-#include "ash/shell.h"
-#include "ui/aura/window.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
-#include "ui/events/event.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/wm/core/coordinate_conversion.h"
-
-namespace ash {
-
-ShelfBezelEventHandler::ShelfBezelEventHandler(Shelf* shelf)
-    : shelf_(shelf), in_touch_drag_(false) {
-  Shell::Get()->AddPreTargetHandler(this);
-}
-
-ShelfBezelEventHandler::~ShelfBezelEventHandler() {
-  Shell::Get()->RemovePreTargetHandler(this);
-}
-
-void ShelfBezelEventHandler::OnGestureEvent(ui::GestureEvent* event) {
-  gfx::Point point_in_screen(event->location());
-  aura::Window* target = static_cast<aura::Window*>(event->target());
-  ::wm::ConvertPointToScreen(target, &point_in_screen);
-  gfx::Rect screen = display::Screen::GetScreen()
-                         ->GetDisplayNearestPoint(point_in_screen)
-                         .bounds();
-  if ((!screen.Contains(point_in_screen) &&
-       IsShelfOnBezel(screen, point_in_screen)) ||
-      in_touch_drag_) {
-    if (shelf_->ProcessGestureEvent(*event)) {
-      switch (event->type()) {
-        case ui::ET_GESTURE_SCROLL_BEGIN:
-          in_touch_drag_ = true;
-          break;
-        case ui::ET_GESTURE_SCROLL_END:
-        case ui::ET_SCROLL_FLING_START:
-          in_touch_drag_ = false;
-          break;
-        default:
-          break;
-      }
-      event->StopPropagation();
-    }
-  }
-}
-
-void ShelfBezelEventHandler::OnTouchEvent(ui::TouchEvent* event) {
-  if (shelf_->auto_hide_behavior() != SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS)
-    return;
-
-  // The event target should be the shelf widget.
-  aura::Window* target = static_cast<aura::Window*>(event->target());
-  if (target != Shelf::ForWindow(target)->shelf_widget()->GetNativeView())
-    return;
-
-  // The touch-pressing event may hide the shelf. Lock the shelf's auto hide
-  // state to give the shelf a chance to handle the touch event before it being
-  // hidden.
-  ShelfLayoutManager* shelf_layout_manager = shelf_->shelf_layout_manager();
-  if (event->type() == ui::ET_TOUCH_PRESSED && shelf_->IsVisible()) {
-    shelf_layout_manager->LockAutoHideState(true);
-  } else if (event->type() == ui::ET_TOUCH_RELEASED ||
-             event->type() == ui::ET_TOUCH_CANCELLED) {
-    shelf_layout_manager->LockAutoHideState(false);
-  }
-}
-
-bool ShelfBezelEventHandler::IsShelfOnBezel(const gfx::Rect& screen,
-                                            const gfx::Point& point) const {
-  switch (shelf_->alignment()) {
-    case SHELF_ALIGNMENT_BOTTOM:
-    case SHELF_ALIGNMENT_BOTTOM_LOCKED:
-      return point.y() >= screen.bottom();
-    case SHELF_ALIGNMENT_LEFT:
-      return point.x() <= screen.x();
-    case SHELF_ALIGNMENT_RIGHT:
-      return point.x() >= screen.right();
-  }
-  NOTREACHED();
-  return false;
-}
-
-}  // namespace ash
diff --git a/ash/shelf/shelf_bezel_event_handler.h b/ash/shelf/shelf_bezel_event_handler.h
deleted file mode 100644
index 3f4ffe3..0000000
--- a/ash/shelf/shelf_bezel_event_handler.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2013 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.
-
-#ifndef ASH_SHELF_SHELF_BEZEL_EVENT_HANDLER_H_
-#define ASH_SHELF_SHELF_BEZEL_EVENT_HANDLER_H_
-
-#include "base/macros.h"
-#include "ui/events/event_handler.h"
-
-namespace gfx {
-class Point;
-class Rect;
-}
-
-namespace ash {
-class Shelf;
-
-// Forwards touch gestures on a bezel sensor to the shelf.
-class ShelfBezelEventHandler : public ui::EventHandler {
- public:
-  explicit ShelfBezelEventHandler(Shelf* shelf);
-  ~ShelfBezelEventHandler() override;
-
-  // Overridden from ui::EventHandler:
-  void OnGestureEvent(ui::GestureEvent* event) override;
-  void OnTouchEvent(ui::TouchEvent* event) override;
-
- private:
-  bool IsShelfOnBezel(const gfx::Rect& screen, const gfx::Point& point) const;
-
-  Shelf* shelf_;
-  bool in_touch_drag_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShelfBezelEventHandler);
-};
-
-}  // namespace ash
-
-#endif  // ASH_SHELF_SHELF_BEZEL_EVENT_HANDLER_H_
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 6a2fbc4..c8f9b9b 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -726,16 +726,9 @@
   EXPECT_EQ(window_bounds_with_noshelf.ToString(), window->bounds().ToString());
   EXPECT_EQ(shelf_hidden.ToString(),
             GetShelfWidget()->GetWindowBoundsInScreen().ToString());
-  // Swipe up from below the shelf where a bezel would be, this should show the
-  // shelf.
+  // Swipe up from the bottom of the shelf, this should show the shelf.
   gfx::Point below_start = edge_to_hide;
-  if (shelf->IsHorizontalAlignment())
-    below_start.set_y(GetShelfWidget()->GetWindowBoundsInScreen().bottom() - 1);
-  else if (SHELF_ALIGNMENT_LEFT == shelf->alignment())
-    below_start.set_x(GetShelfWidget()->GetWindowBoundsInScreen().x());
-  else if (SHELF_ALIGNMENT_RIGHT == shelf->alignment())
-    below_start.set_x(GetShelfWidget()->GetWindowBoundsInScreen().right() - 1);
-  generator->GestureScrollSequence(below_start, edge_to_show, kTimeDelta,
+  generator->GestureScrollSequence(edge_to_hide, edge_to_show, kTimeDelta,
                                    kNumScrollSteps);
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
@@ -2247,8 +2240,9 @@
     ui::ScopedAnimationDurationScaleMode regular_animations(
         ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
 
-    gfx::Point start =
-        GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
+    display::Display display =
+        display::Screen::GetScreen()->GetPrimaryDisplay();
+    gfx::Point start = display.bounds().bottom_center();
     gfx::Point end(start.x(), start.y() - 100);
     ui::test::EventGenerator* generator = GetEventGenerator();
 
@@ -2286,11 +2280,8 @@
     // Show the shelf first.
     display::Display display =
         display::Screen::GetScreen()->GetPrimaryDisplay();
-    const int half_width = display.bounds().width() / 2;
-    const int bottom_edge = display.bounds().bottom();
-    generator->MoveMouseTo(half_width,
-                           bottom_edge - kHiddenShelfInScreenPortion / 2);
     ShelfAnimationWaiter waiter1(visible_bounds);
+    generator->MoveMouseTo(display.bounds().bottom_center());
     waiter1.WaitTillDoneAnimating();
     EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
 
@@ -2346,7 +2337,8 @@
 
   wm::GetWindowState(window_two)
       ->set_autohide_shelf_when_maximized_or_fullscreen(true);
-  window_two->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  window_two->SetProperty(aura::client::kZOrderingKey,
+                          ui::ZOrderLevel::kFloatingWindow);
 
   auto* shelf_window = shelf->GetWindow();
   aura::Window* container = shelf_window->GetRootWindow()->GetChildById(
@@ -2842,7 +2834,6 @@
 
   const int time_deltas[] = {10, 50, 100, 500};
   const int num_scroll_steps[] = {2, 5, 10, 50};
-  const int y_bezel_start_offsets[] = {5, 10, 50};
   const int x_offsets[] = {10, 20, 50};
   const int y_offsets[] = {70, 100, 300, 500};
 
@@ -2850,21 +2841,17 @@
     for (int num_scroll_steps : num_scroll_steps) {
       for (int x_offset : x_offsets) {
         for (int y_offset : y_offsets) {
-          for (int y_bezel_start_offset : y_bezel_start_offsets) {
-            const gfx::Point start(display_bounds.bottom_center() +
-                                   gfx::Vector2d(0, y_bezel_start_offset));
-            const gfx::Point end(start + gfx::Vector2d(x_offset, -y_offset));
-            generator->GestureScrollSequence(
-                start, end, base::TimeDelta::FromMilliseconds(time_delta),
-                num_scroll_steps);
-            EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState())
-                << "Failure to show shelf after a swipe up in " << time_delta
-                << "ms, " << num_scroll_steps << " steps, "
-                << y_bezel_start_offset << " Y bezel start offset, " << x_offset
-                << " X-offset and " << y_offset << " Y-offset.";
-            generator->GestureTapAt(tap_to_hide_shelf_location);
-            EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
-          }
+          const gfx::Point start(display_bounds.bottom_center());
+          const gfx::Point end(start + gfx::Vector2d(x_offset, -y_offset));
+          generator->GestureScrollSequence(
+              start, end, base::TimeDelta::FromMilliseconds(time_delta),
+              num_scroll_steps);
+          EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState())
+              << "Failure to show shelf after a swipe up in " << time_delta
+              << "ms, " << num_scroll_steps << " steps, " << x_offset
+              << " X-offset and " << y_offset << " Y-offset.";
+          generator->GestureTapAt(tap_to_hide_shelf_location);
+          EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
         }
       }
     }
@@ -3090,7 +3077,8 @@
   aura::Window* window = CreateTestWindow();
   window->SetBounds(gfx::Rect(0, 0, 100, 100));
   // Set always on top so it is put in the PIP container.
-  window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  window->SetProperty(aura::client::kZOrderingKey,
+                      ui::ZOrderLevel::kFloatingWindow);
   window->Show();
   const wm::WMEvent pip_event(wm::WM_EVENT_PIP);
   wm::GetWindowState(window)->OnWMEvent(&pip_event);
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 47def11..2e9f451 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -338,10 +338,9 @@
 // static
 const int ShelfView::kMinimumDragDistance = 8;
 
-ShelfView::ShelfView(ShelfModel* model, Shelf* shelf, ShelfWidget* shelf_widget)
+ShelfView::ShelfView(ShelfModel* model, Shelf* shelf)
     : model_(model),
       shelf_(shelf),
-      shelf_widget_(shelf_widget),
       view_model_(std::make_unique<views::ViewModel>()),
       bounds_animator_(std::make_unique<views::BoundsAnimator>(this)),
       tooltip_(this),
@@ -349,7 +348,6 @@
       weak_factory_(this) {
   DCHECK(model_);
   DCHECK(shelf_);
-  DCHECK(shelf_widget_);
   Shell::Get()->tablet_mode_controller()->AddObserver(this);
   Shell::Get()->system_tray_model()->virtual_keyboard()->AddObserver(this);
   Shell::Get()->AddShellObserver(this);
@@ -525,7 +523,7 @@
   if (!overflow_bubble_)
     overflow_bubble_.reset(new OverflowBubble(shelf_));
 
-  ShelfView* overflow_view = new ShelfView(model_, shelf_, shelf_widget_);
+  ShelfView* overflow_view = new ShelfView(model_, shelf_);
   overflow_view->overflow_mode_ = true;
   overflow_view->Init();
   overflow_view->set_owner_overflow_bubble(overflow_bubble_.get());
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index d9e5621..c7f61a8 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -18,6 +18,7 @@
 #include "ash/public/cpp/tablet_mode_observer.h"
 #include "ash/shelf/overflow_bubble.h"
 #include "ash/shelf/overflow_bubble_view.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_button_delegate.h"
 #include "ash/shelf/shelf_button_pressed_metric_tracker.h"
 #include "ash/shelf/shelf_tooltip_manager.h"
@@ -54,7 +55,6 @@
 class OverflowBubble;
 class OverflowButton;
 class ScopedRootWindowForNewWindows;
-class Shelf;
 class ShelfAppButton;
 class ShelfButton;
 class ShelfModel;
@@ -118,7 +118,7 @@
                              public ash::TabletModeObserver,
                              public VirtualKeyboardModel::Observer {
  public:
-  ShelfView(ShelfModel* model, Shelf* shelf, ShelfWidget* shelf_widget);
+  ShelfView(ShelfModel* model, Shelf* shelf);
   ~ShelfView() override;
 
   Shelf* shelf() const { return shelf_; }
@@ -315,7 +315,7 @@
     else
       return std::max(0, last_visible_index_ + 1);
   }
-  ShelfWidget* shelf_widget() const { return shelf_widget_; }
+  ShelfWidget* shelf_widget() const { return shelf_->shelf_widget(); }
   OverflowBubble* overflow_bubble() { return overflow_bubble_.get(); }
   views::ViewModel* view_model() { return view_model_.get(); }
 
@@ -547,10 +547,6 @@
   // The shelf controller; owned by RootWindowController.
   Shelf* shelf_;
 
-  // The shelf widget for this view. For overflow bubbles, this is the widget
-  // for the shelf, not for the bubble.
-  ShelfWidget* shelf_widget_;
-
   // Used to manage the set of active launcher buttons. There is a view per
   // item in |model_|.
   std::unique_ptr<views::ViewModel> view_model_;
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 5b90c8b..e12dfada 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -5,6 +5,7 @@
 #include "ash/shelf/shelf_view.h"
 
 #include <algorithm>
+#include <cmath>
 #include <memory>
 #include <utility>
 #include <vector>
@@ -511,7 +512,7 @@
     ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
   }
 
-  void AddButtonsUntilOverflow() {
+  void AddAppShortcutsUntilOverflow() {
     int items_added = 0;
     while (!shelf_view_->GetOverflowButton()->GetVisible()) {
       AddAppShortcut();
@@ -710,7 +711,7 @@
 // Check the ideal bounds of several items in LTR and RTL UI.
 TEST_P(ShelfViewTextDirectionTest, GetIdealBoundsOfItemIcon) {
   ShelfID id_1 = AddAppShortcut();
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   ShelfID id_2 = AddAppShortcut();
   ShelfID id_3 = AddAppShortcut();
 
@@ -761,7 +762,7 @@
 }
 
 TEST_F(ShelfViewTest, OverflowVisibleIndex) {
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   ASSERT_TRUE(shelf_view_->GetOverflowButton()->GetVisible());
   const int last_visible_index = shelf_view_->last_visible_index();
 
@@ -925,7 +926,7 @@
   };
 
   // Setup the shelf so the overflow bubble is visible.
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   test_api_->ShowOverflowBubble();
   ShelfViewTestAPI overflow_test_api(
       test_api_->overflow_bubble()->bubble_view()->shelf_view());
@@ -1171,7 +1172,7 @@
   // overflow. Add one more app (which is on the overflow shelf).
   ShelfID first_app_id = AddAppShortcut();
   ShelfID second_app_id = AddAppShortcut();
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   ShelfID overflow_app_id = AddAppShortcut();
 
   // Verify that dragging an app off the shelf will trigger the app getting
@@ -1328,7 +1329,7 @@
 }
 
 TEST_F(ShelfViewTest, ButtonTitlesTest) {
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   EXPECT_EQ(base::UTF8ToUTF16("Launcher"),
             shelf_view_->GetHomeButton()->GetAccessibleName());
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_SHELF_BACK_BUTTON_TITLE),
@@ -1561,7 +1562,7 @@
 
 // Checks the overflow bubble size when an item is ripped off and re-inserted.
 TEST_F(ShelfViewTest, OverflowBubbleSize) {
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   // Add one more button to prevent the overflow bubble to disappear upon
   // dragging an item out on windows (flakiness, see crbug.com/436131).
   AddAppShortcut();
@@ -1619,7 +1620,7 @@
   const SkColor opaque_expected_color =
       wallpaper_test_api.ApplyColorProducingWallpaper();
 
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   test_api_->ShowOverflowBubble();
   OverflowBubbleView* bubble_view = test_api_->overflow_bubble()->bubble_view();
 
@@ -1630,7 +1631,7 @@
 TEST_F(ShelfViewTest, CheckDragInsertBoundsOfScrolledOverflowBubble) {
   UpdateDisplay("400x300");
 
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
 
   // Show overflow bubble.
   test_api_->ShowOverflowBubble();
@@ -1714,7 +1715,7 @@
   // Speeds up animation for test.
   test_api_for_secondary.SetAnimationDuration(1);
 
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
 
   // Test #1: Test drag insertion bounds of primary shelf.
   // Show overflow bubble.
@@ -1769,32 +1770,41 @@
 // Verifies that the arrow buttons of OverflowBubbleView work as expected.
 TEST_F(ShelfViewTest, CheckOverflowBubbleViewArrowButton) {
   UpdateDisplay("300x600");
-  AddButtonsUntilOverflow();
-
-  // Add enough shelf items to test the arrow button.
-  for (int i = 0; i < 5; i++)
-    AddAppShortcut();
+  AddAppShortcutsUntilOverflow();
 
   // Show overflow bubble.
   test_api_->ShowOverflowBubble();
   ASSERT_TRUE(shelf_view_->IsShowingOverflowBubble());
 
   OverflowBubbleView* bubble_view = test_api_->overflow_bubble()->bubble_view();
-  int item_count = bubble_view->shelf_view()->last_visible_index() -
-                   bubble_view->shelf_view()->first_visible_index() + 1;
-  ASSERT_EQ(7, item_count);
-  OverflowBubbleViewTestAPI bubble_view_api(bubble_view);
-  views::View* left_arrow_button = bubble_view->left_arrow();
-  views::View* right_arrow_button = bubble_view->right_arrow();
-  ShelfViewTestAPI test_for_overflow_view(
-      test_api_->overflow_bubble()->bubble_view()->shelf_view());
-  const gfx::Rect overflow_bubble_bounds = bubble_view->GetBoundsInScreen();
   const gfx::Size shelf_icon_size(kShelfButtonSize, kShelfButtonSize);
   const int arrow_button_size = OverflowBubbleView::kArrowButtonSize;
   const int bubble_view_min_margin = OverflowBubbleView::kMinimumMargin;
   const int end_padding = OverflowBubbleView::kEndPadding;
   const int unit = kShelfButtonSize + kShelfButtonSpacing;
 
+  // Add sufficient app icons to ensure that it needs to press the right arrow
+  // buttons twice to reach the end.
+  int current_item_count = bubble_view->shelf_view()->last_visible_index() -
+                           bubble_view->shelf_view()->first_visible_index() + 1;
+  const int available_width_for_shortcuts =
+      GetPrimaryDisplay().work_area().width() - 2 * bubble_view_min_margin -
+      2 * end_padding;
+  const int max_accommodated_shelf_num =
+      std::ceil(available_width_for_shortcuts / unit);
+  int additional_item_num =
+      2 * max_accommodated_shelf_num - 1 - current_item_count;
+  while (additional_item_num) {
+    AddAppShortcut();
+    additional_item_num--;
+  }
+
+  const gfx::Rect overflow_bubble_bounds = bubble_view->GetBoundsInScreen();
+  views::View* left_arrow_button = bubble_view->left_arrow();
+  views::View* right_arrow_button = bubble_view->right_arrow();
+  ShelfViewTestAPI test_for_overflow_view(
+      test_api_->overflow_bubble()->bubble_view()->shelf_view());
+
   // Verifies that the overflow bubble has the correct bounds. In detail:
   // (1) The width of the overflow bubble should be the multiple of |unit|.
   // (2) The overflow bubble's gap between left and right display edge should
@@ -1802,9 +1812,9 @@
   EXPECT_EQ(
       overflow_bubble_bounds.origin().x(),
       GetPrimaryDisplay().bounds().right() - overflow_bubble_bounds.right());
-  const int available_width =
+  const int available_width_for_bubble =
       GetPrimaryDisplay().bounds().width() - 2 * bubble_view_min_margin;
-  const int rd = available_width % unit;
+  const int rd = available_width_for_bubble % unit;
   EXPECT_EQ(rd / 2 + bubble_view_min_margin,
             overflow_bubble_bounds.origin().x());
   EXPECT_EQ(0, overflow_bubble_bounds.width() % unit);
@@ -1830,7 +1840,6 @@
   const gfx::Point right_button_center =
       right_arrow_button->GetBoundsInScreen().CenterPoint();
   GetEventGenerator()->GestureTapAt(right_button_center);
-  base::RunLoop().RunUntilIdle();
 
   // Verifies that the layout strategy is SHOW_BUTTONS.
   EXPECT_EQ(OverflowBubbleView::SHOW_BUTTONS, bubble_view->layout_strategy());
@@ -1863,7 +1872,6 @@
   // (3) The right button is invisible.
   // (4) The last visible shelf button has the expected bounds in screen.
   GetEventGenerator()->GestureTapAt(right_button_center);
-  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(OverflowBubbleView::SHOW_LEFT_ARROW_BUTTON,
             bubble_view->layout_strategy());
   EXPECT_FALSE(right_arrow_button->GetVisible());
@@ -1890,6 +1898,72 @@
   EXPECT_FALSE(left_arrow_button->GetVisible());
 }
 
+// Verifies that the overflow bubble view handles the gesture events correctly.
+TEST_F(ShelfViewTest, CheckGestureDraggingOverflowBubbleView) {
+  UpdateDisplay("300x600");
+  AddAppShortcutsUntilOverflow();
+
+  // Show overflow bubble.
+  test_api_->ShowOverflowBubble();
+  ASSERT_TRUE(shelf_view_->IsShowingOverflowBubble());
+  OverflowBubbleView* bubble_view = test_api_->overflow_bubble()->bubble_view();
+
+  const int bubble_view_min_margin = OverflowBubbleView::kMinimumMargin;
+  const int end_padding = OverflowBubbleView::kEndPadding;
+  const int unit = kShelfButtonSize + kShelfButtonSpacing;
+
+  // Calculates the start point of the gesture drag event. Ensures that the
+  // start point is not within the bounds of any shelf icon.
+  ShelfViewTestAPI test_for_overflow_view(
+      test_api_->overflow_bubble()->bubble_view()->shelf_view());
+  const gfx::Rect first_icon_bounds =
+      test_for_overflow_view
+          .GetButton(bubble_view->shelf_view()->first_visible_index())
+          ->GetBoundsInScreen();
+  gfx::Point gesture_drag_point = first_icon_bounds.right_center();
+  gesture_drag_point.Offset(1, 0);
+
+  // Verifies that gesture dragging is disabled when no arrow button shows.
+  ASSERT_EQ(OverflowBubbleView::NOT_SHOW_ARROW_BUTTON,
+            bubble_view->layout_strategy());
+  gfx::Point gesture_end_point = gesture_drag_point;
+  gesture_end_point.Offset(-kShelfButtonSize, 0);
+  GetEventGenerator()->GestureScrollSequence(
+      gesture_drag_point, gesture_end_point,
+      base::TimeDelta::FromMilliseconds(100), 5);
+  EXPECT_EQ(0, bubble_view->scroll_offset().x());
+
+  // Adds enough shelf icons to show the right arrow button.
+  const int available_width_for_shortcuts =
+      GetPrimaryDisplay().bounds().width() - 2 * bubble_view_min_margin -
+      2 * end_padding;
+  int max_accommodated_shelf_num =
+      std::ceil(available_width_for_shortcuts / unit);
+  while (max_accommodated_shelf_num) {
+    AddAppShortcut();
+    max_accommodated_shelf_num--;
+  }
+  ASSERT_EQ(OverflowBubbleView::SHOW_RIGHT_ARROW_BUTTON,
+            bubble_view->layout_strategy());
+
+  // Verifies that the small gesutre offset will not scroll the overflow bubble.
+  gesture_end_point = gesture_drag_point;
+  gesture_end_point.Offset(-10, 0);
+  GetEventGenerator()->GestureScrollSequence(
+      gesture_drag_point, gesture_end_point,
+      base::TimeDelta::FromMilliseconds(100), 1);
+  EXPECT_EQ(0, bubble_view->scroll_offset().x());
+
+  // Verifies that the large gesture offset will scroll the overflow bubble. The
+  // scroll offset is adjusted to fully show all of shelf icons.
+  gesture_end_point = gesture_drag_point;
+  gesture_end_point.Offset(-kShelfButtonSize, 0);
+  GetEventGenerator()->GestureScrollSequence(
+      gesture_drag_point, gesture_end_point,
+      base::TimeDelta::FromMilliseconds(100), 1);
+  EXPECT_EQ(unit, bubble_view->scroll_offset().x());
+}
+
 // Checks the rip an item off from left aligned shelf in secondary monitor.
 TEST_F(ShelfViewTest, CheckRipOffFromLeftShelfAlignmentWithMultiMonitor) {
   UpdateDisplay("800x600,800x600");
@@ -1928,7 +2002,7 @@
 // Checks various drag and drop operations from OverflowBubble to Shelf, and
 // vice versa.
 TEST_F(ShelfViewTest, CheckDragAndDropFromShelfToOtherShelf) {
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   // Add one more button to prevent the overflow bubble to disappear upon
   // dragging an item out on windows (flakiness, see crbug.com/425097).
   AddAppShortcut();
@@ -1947,7 +2021,7 @@
 // Checks drag-reorder items within the overflow shelf.
 TEST_F(ShelfViewTest, TestDragWithinOverflow) {
   // Prepare the overflow and open it.
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   // Add a couple more to make sure we have things to drag.
   AddAppShortcut();
   AddAppShortcut();
@@ -1994,7 +2068,7 @@
 // Checks creating app shortcut for an opened platform app in overflow bubble
 // should be invisible to the shelf. See crbug.com/605793.
 TEST_F(ShelfViewTest, CheckOverflowStatusPinOpenedAppToShelf) {
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
 
   // Add a running Platform app.
   ShelfID platform_app_id = AddApp();
@@ -2068,7 +2142,7 @@
   // overflow. Add two more apps (which are on the overflow shelf).
   ShelfID first_app_id = AddAppShortcut();
   ShelfID second_app_id = AddAppShortcut();
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   ShelfID overflow_app_id1 = AddAppShortcut();
   ShelfID overflow_app_id2 = AddAppShortcut();
 
@@ -2138,7 +2212,7 @@
 TEST_F(ShelfViewTest, UnpinningCancelsOverflow) {
   // Add just enough items for overflow; one fewer would not require overflow.
   const ShelfID first_shelf_id = AddAppShortcut();
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   test_api_->ShowOverflowBubble();
   EXPECT_TRUE(shelf_view_->GetOverflowButton()->GetVisible());
   EXPECT_TRUE(shelf_view_->IsShowingOverflowBubble());
@@ -2262,7 +2336,7 @@
 // Tests that the overflow button does not show a context menu.
 TEST_F(ShelfViewTest, NoContextMenuOnOverflowButton) {
   ui::test::EventGenerator* generator = GetEventGenerator();
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   views::View* overflow_button = shelf_view_->GetOverflowButton();
 
   generator->MoveMouseTo(overflow_button->GetBoundsInScreen().CenterPoint());
@@ -3249,7 +3323,7 @@
     views::test::InkDropHostViewTestApi(overflow_button_)
         .SetInkDrop(std::move(overflow_button_ink_drop));
 
-    AddButtonsUntilOverflow();
+    AddAppShortcutsUntilOverflow();
     EXPECT_TRUE(shelf_view_->GetOverflowButton()->GetVisible());
     EXPECT_FALSE(shelf_view_->IsShowingOverflowBubble());
   }
@@ -3775,7 +3849,7 @@
   std::unique_ptr<aura::Window> window = CreateTestWindow();
   ::wm::ActivateWindow(window.get());
 
-  AddButtonsUntilOverflow();
+  AddAppShortcutsUntilOverflow();
   test_api_->ShowOverflowBubble();
   EXPECT_TRUE(::wm::IsActiveWindow(window.get()));
 }
@@ -3827,7 +3901,7 @@
 
     // Add app shortcuts until the overflow button is visible. At this point
     // there will be two items on the overflow shelf.
-    AddButtonsUntilOverflow();
+    AddAppShortcutsUntilOverflow();
 
     // Add two more shortcuts for a total of four items on the overflow shelf.
     AddAppShortcut();
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index c876d520..68c4308 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -304,7 +304,7 @@
                            Shell::Get()->wallpaper_controller()),
       shelf_layout_manager_(new ShelfLayoutManager(this, shelf)),
       delegate_view_(new DelegateView(this)),
-      shelf_view_(new ShelfView(ShelfModel::Get(), shelf_, this)),
+      shelf_view_(new ShelfView(ShelfModel::Get(), shelf_)),
       login_shelf_view_(
           new LoginShelfView(RootWindowController::ForWindow(shelf_container)
                                  ->lock_screen_action_background_controller())),
diff --git a/ash/shell.cc b/ash/shell.cc
index 7816356..0a70bec 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -56,7 +56,6 @@
 #include "ash/ime/ime_controller.h"
 #include "ash/keyboard/keyboard_controller_impl.h"
 #include "ash/keyboard/ui/keyboard_ui_factory.h"
-#include "ash/kiosk_next/kiosk_next_shell_controller_impl.h"
 #include "ash/laser/laser_pointer_controller.h"
 #include "ash/login/login_screen_controller.h"
 #include "ash/login_status.h"
@@ -713,9 +712,6 @@
   // Close all widgets (including the shelf) and destroy all window containers.
   CloseAllRootWindowChildWindows();
 
-  // Destruct KioskNextShellController after Shelf
-  kiosk_next_shell_controller_.reset();
-
   login_screen_controller_.reset();
   system_notification_controller_.reset();
   // Should be destroyed after Shelf and |system_notification_controller_|.
@@ -896,8 +892,7 @@
         std::make_unique<MultiDeviceNotificationPresenter>(
             message_center::MessageCenter::Get(), connector_);
   }
-  kiosk_next_shell_controller_ =
-      std::make_unique<KioskNextShellControllerImpl>();
+
   tablet_mode_controller_ = std::make_unique<TabletModeController>();
 
   accessibility_focus_ring_controller_ =
diff --git a/ash/shell.h b/ash/shell.h
index ae376fd..f964dd0 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -129,7 +129,6 @@
 class ImmersiveContext;
 class KeyAccessibilityEnabler;
 class KeyboardBrightnessControlDelegate;
-class KioskNextShellControllerImpl;
 class KeyboardControllerImpl;
 class LaserPointerController;
 class LocaleUpdateControllerImpl;
@@ -381,9 +380,6 @@
   KeyboardBrightnessControlDelegate* keyboard_brightness_control_delegate() {
     return keyboard_brightness_control_delegate_.get();
   }
-  KioskNextShellControllerImpl* kiosk_next_shell_controller() {
-    return kiosk_next_shell_controller_.get();
-  }
   KeyboardControllerImpl* keyboard_controller() {
     return keyboard_controller_.get();
   }
@@ -667,7 +663,6 @@
   std::unique_ptr<ImmersiveContext> immersive_context_;
   std::unique_ptr<KeyboardBrightnessControlDelegate>
       keyboard_brightness_control_delegate_;
-  std::unique_ptr<KioskNextShellControllerImpl> kiosk_next_shell_controller_;
   std::unique_ptr<LocaleUpdateControllerImpl> locale_update_controller_;
   std::unique_ptr<LoginScreenController> login_screen_controller_;
   std::unique_ptr<LogoutConfirmationController> logout_confirmation_controller_;
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc
index b1fc2e0..31c4252 100644
--- a/ash/shell_unittest.cc
+++ b/ash/shell_unittest.cc
@@ -195,7 +195,8 @@
                         bool always_on_top,
                         aura::Window* expected_container) {
     views::Widget::InitParams widget_params(type);
-    widget_params.keep_on_top = always_on_top;
+    if (always_on_top)
+      widget_params.z_order = ui::ZOrderLevel::kFloatingWindow;
 
     views::Widget* widget = CreateTestWindow(widget_params);
     widget->Show();
@@ -281,11 +282,11 @@
             widget.GetRestoredBounds().CenterPoint());
 }
 
-TEST_F(ShellTest, ChangeAlwaysOnTop) {
+TEST_F(ShellTest, ChangeZOrderLevel) {
   views::Widget::InitParams widget_params(
       views::Widget::InitParams::TYPE_WINDOW);
 
-  // Creates a normal window
+  // Creates a normal window.
   views::Widget* widget = CreateTestWindow(widget_params);
   widget->Show();
 
@@ -293,19 +294,19 @@
   EXPECT_TRUE(
       GetActiveDeskContainer()->Contains(widget->GetNativeWindow()->parent()));
 
-  // Flip always-on-top flag.
-  widget->SetAlwaysOnTop(true);
+  // Set the z-order to float.
+  widget->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
   // And it should in always on top container now.
   EXPECT_EQ(GetAlwaysOnTopContainer(), widget->GetNativeWindow()->parent());
 
-  // Flip always-on-top flag.
-  widget->SetAlwaysOnTop(false);
+  // Put the z-order back to normal.
+  widget->SetZOrderLevel(ui::ZOrderLevel::kNormal);
   // It should go back to the active desk container.
   EXPECT_TRUE(
       GetActiveDeskContainer()->Contains(widget->GetNativeWindow()->parent()));
 
-  // Set the same always-on-top flag again.
-  widget->SetAlwaysOnTop(false);
+  // Set the z-order again to the normal value.
+  widget->SetZOrderLevel(ui::ZOrderLevel::kNormal);
   // Should have no effect and we are still in the the active desk container.
   EXPECT_TRUE(
       GetActiveDeskContainer()->Contains(widget->GetNativeWindow()->parent()));
diff --git a/ash/sticky_keys/sticky_keys_overlay.cc b/ash/sticky_keys/sticky_keys_overlay.cc
index cc96f1f..b86db12 100644
--- a/ash/sticky_keys/sticky_keys_overlay.cc
+++ b/ash/sticky_keys/sticky_keys_overlay.cc
@@ -211,7 +211,7 @@
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.accept_events = false;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.bounds = CalculateOverlayBounds();
   params.parent = Shell::GetContainer(Shell::GetRootWindowForNewWindows(),
                                       kShellWindowId_OverlayContainer);
diff --git a/ash/system/power/power_button_controller.cc b/ash/system/power/power_button_controller.cc
index 6bcda10..f71e4c6 100644
--- a/ash/system/power/power_button_controller.cc
+++ b/ash/system/power/power_button_controller.cc
@@ -64,7 +64,7 @@
   views::Widget::InitParams params(
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingWindow;
   params.accept_events = true;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.name = "PowerButtonMenuWindow";
diff --git a/ash/system/session/logout_confirmation_controller_unittest.cc b/ash/system/session/logout_confirmation_controller_unittest.cc
index c74750c..1ca732e 100644
--- a/ash/system/session/logout_confirmation_controller_unittest.cc
+++ b/ash/system/session/logout_confirmation_controller_unittest.cc
@@ -286,7 +286,7 @@
 
   // Moving the widget to the always-on-top container does not trigger the
   // dialog because the window didn't close.
-  widget->SetAlwaysOnTop(true);
+  widget->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
   EXPECT_FALSE(controller->dialog_for_testing());
 
   // Closing the window triggers the dialog.
@@ -302,7 +302,7 @@
   // Create two windows in different containers.
   std::unique_ptr<views::Widget> normal_widget = CreateTestWidget();
   std::unique_ptr<views::Widget> always_on_top_widget = CreateTestWidget();
-  always_on_top_widget->SetAlwaysOnTop(true);
+  always_on_top_widget->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
 
   // Closing the last window shows the dialog.
   always_on_top_widget.reset();
diff --git a/ash/system/toast/toast_overlay.cc b/ash/system/toast/toast_overlay.cc
index bc0aa60c..26450a5 100644
--- a/ash/system/toast/toast_overlay.cc
+++ b/ash/system/toast/toast_overlay.cc
@@ -231,7 +231,7 @@
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.accept_events = true;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.bounds = CalculateOverlayBounds();
   // Show toasts above the app list and below the lock screen.
   params.parent = Shell::GetRootWindowForNewWindows()->GetChildById(
diff --git a/ash/system/tray/tray_event_filter.cc b/ash/system/tray/tray_event_filter.cc
index ea8827a..e291bf0 100644
--- a/ash/system/tray/tray_event_filter.cc
+++ b/ash/system/tray/tray_event_filter.cc
@@ -63,7 +63,7 @@
     // from message center.
     if (container_id == kShellWindowId_StatusContainer &&
         target->type() == aura::client::WINDOW_TYPE_POPUP && target_widget &&
-        target_widget->IsAlwaysOnTop()) {
+        target_widget->GetZOrderLevel() != ui::ZOrderLevel::kNormal) {
       return;
     }
     // Don't process events that occurred inside a virtual keyboard.
diff --git a/ash/system/tray/tray_event_filter_unittest.cc b/ash/system/tray/tray_event_filter_unittest.cc
index 1706348d..550e63ea 100644
--- a/ash/system/tray/tray_event_filter_unittest.cc
+++ b/ash/system/tray/tray_event_filter_unittest.cc
@@ -109,8 +109,8 @@
       CreateTestWindow(gfx::Rect(), aura::client::WINDOW_TYPE_POPUP);
   popup_window->set_owned_by_parent(false);
   popup_widget->GetNativeView()->AddChild(popup_window.get());
-  popup_widget->GetNativeView()->SetProperty(aura::client::kAlwaysOnTopKey,
-                                             true);
+  popup_widget->GetNativeView()->SetProperty(aura::client::kZOrderingKey,
+                                             ui::ZOrderLevel::kFloatingWindow);
 
   ShowSystemTrayMainView();
   EXPECT_TRUE(IsBubbleShown());
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 78ca236..351eebb 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -86,8 +86,9 @@
   // lap with the native mouse cursor.
   if (!command_line_->GetProcessCommandLine()->HasSwitch(
           ::switches::kHostWindowBounds)) {
+    // TODO(oshima): Disable native events instead of adding offset.
     command_line_->GetProcessCommandLine()->AppendSwitchASCII(
-        ::switches::kHostWindowBounds, "1+1-800x600");
+        ::switches::kHostWindowBounds, "10+10-800x600");
   }
 
   // Pre shell creation config init.
diff --git a/ash/wm/always_on_top_controller.cc b/ash/wm/always_on_top_controller.cc
index 92b1798..f41a9d9 100644
--- a/ash/wm/always_on_top_controller.cc
+++ b/ash/wm/always_on_top_controller.cc
@@ -44,7 +44,11 @@
   DCHECK(always_on_top_container_);
   DCHECK(pip_container_);
 
-  if (!window->GetProperty(aura::client::kAlwaysOnTopKey)) {
+  // On other platforms, there are different window levels. For now, treat any
+  // window with non-normal level as "always on top". Perhaps the nuance of
+  // multiple levels will be needed later.
+  if (window->GetProperty(aura::client::kZOrderingKey) ==
+      ui::ZOrderLevel::kNormal) {
     aura::Window* root = always_on_top_container_->GetRootWindow();
 
     // TODO(afakhry): Do we need to worry about the context of |window| here? Or
@@ -103,7 +107,7 @@
                                                     const void* key,
                                                     intptr_t old) {
   if (window != always_on_top_container_ && window != pip_container_ &&
-      key == aura::client::kAlwaysOnTopKey) {
+      key == aura::client::kZOrderingKey) {
     ReparentWindow(window);
   }
 }
diff --git a/ash/wm/always_on_top_controller_unittest.cc b/ash/wm/always_on_top_controller_unittest.cc
index 28731c5..caee116 100644
--- a/ash/wm/always_on_top_controller_unittest.cc
+++ b/ash/wm/always_on_top_controller_unittest.cc
@@ -80,7 +80,7 @@
 }
 
 TEST_F(AlwaysOnTopControllerTest,
-       AlwaysOnTopContainerReturnedForAlwaysOnTopWindow) {
+       AlwaysOnTopContainerReturnedForFloatingWindow) {
   RootWindowController* controller = Shell::GetPrimaryRootWindowController();
   AlwaysOnTopController* always_on_top_controller =
       controller->always_on_top_controller();
@@ -88,7 +88,8 @@
   const gfx::Rect bounds(100, 100, 200, 200);
   std::unique_ptr<aura::Window> always_on_top_window(
       CreateTestWindowInShellWithBounds(bounds));
-  always_on_top_window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  always_on_top_window->SetProperty(aura::client::kZOrderingKey,
+                                    ui::ZOrderLevel::kFloatingWindow);
 
   aura::Window* container =
       always_on_top_controller->GetContainer(always_on_top_window.get());
@@ -96,7 +97,7 @@
   EXPECT_EQ(kShellWindowId_AlwaysOnTopContainer, container->id());
 }
 
-TEST_F(AlwaysOnTopControllerTest, PipContainerReturnedForAlwaysOnTopPipWindow) {
+TEST_F(AlwaysOnTopControllerTest, PipContainerReturnedForFloatingPipWindow) {
   RootWindowController* controller = Shell::GetPrimaryRootWindowController();
   AlwaysOnTopController* always_on_top_controller =
       controller->always_on_top_controller();
@@ -108,7 +109,8 @@
   wm::WindowState* window_state = wm::GetWindowState(pip_window.get());
   const wm::WMEvent enter_pip(wm::WM_EVENT_PIP);
   window_state->OnWMEvent(&enter_pip);
-  pip_window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  pip_window->SetProperty(aura::client::kZOrderingKey,
+                          ui::ZOrderLevel::kFloatingWindow);
   EXPECT_TRUE(window_state->IsPip());
 
   aura::Window* container =
@@ -134,11 +136,12 @@
 }
 
 TEST_F(AlwaysOnTopControllerTest,
-       AlwaysOnTopWindowMovedBetweenContainersWhenPipStateChanges) {
+       FloatingWindowMovedBetweenContainersWhenPipStateChanges) {
   const gfx::Rect bounds(100, 100, 200, 200);
   std::unique_ptr<aura::Window> window(
       CreateTestWindowInShellWithBounds(bounds));
-  window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  window->SetProperty(aura::client::kZOrderingKey,
+                      ui::ZOrderLevel::kFloatingWindow);
 
   EXPECT_EQ(kShellWindowId_AlwaysOnTopContainer, window->parent()->id());
 
diff --git a/ash/wm/ash_focus_rules_unittest.cc b/ash/wm/ash_focus_rules_unittest.cc
index 89b6c45..43e31b4 100644
--- a/ash/wm/ash_focus_rules_unittest.cc
+++ b/ash/wm/ash_focus_rules_unittest.cc
@@ -112,7 +112,8 @@
   aura::Window* CreateWindowInAlwaysOnTopContainer() {
     aura::Window* window =
         CreateWindowInContainer(kShellWindowId_AlwaysOnTopContainer);
-    window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+    window->SetProperty(aura::client::kZOrderingKey,
+                        ui::ZOrderLevel::kFloatingWindow);
     return window;
   }
 
diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc
index 1578639..2d3baac 100644
--- a/ash/wm/drag_window_resizer_unittest.cc
+++ b/ash/wm/drag_window_resizer_unittest.cc
@@ -83,7 +83,8 @@
 
     always_on_top_window_ = window_factory::NewWindow(&delegate2_);
     always_on_top_window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
-    always_on_top_window_->SetProperty(aura::client::kAlwaysOnTopKey, true);
+    always_on_top_window_->SetProperty(aura::client::kZOrderingKey,
+                                       ui::ZOrderLevel::kFloatingWindow);
     always_on_top_window_->Init(ui::LAYER_NOT_DRAWN);
     ParentWindowInPrimaryRootWindow(always_on_top_window_.get());
     always_on_top_window_->set_id(2);
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index bcdd4ac..7ed98f1b 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -915,10 +915,14 @@
   // Preserves ordering if the category is the same.
   std::sort(items.begin(), items.end(),
             [&selected_item](OverviewItem* a, OverviewItem* b) {
+              // NB: This treats all non-normal z-ordered windows the same. If
+              // Aura ever adopts z-order levels, this will need to be changed.
               const bool a_on_top =
-                  a->GetWindow()->GetProperty(aura::client::kAlwaysOnTopKey);
+                  a->GetWindow()->GetProperty(aura::client::kZOrderingKey) !=
+                  ui::ZOrderLevel::kNormal;
               const bool b_on_top =
-                  b->GetWindow()->GetProperty(aura::client::kAlwaysOnTopKey);
+                  b->GetWindow()->GetProperty(aura::client::kZOrderingKey) !=
+                  ui::ZOrderLevel::kNormal;
               if (selected_item && a_on_top && b_on_top)
                 return a == selected_item;
               if (a_on_top)
diff --git a/ash/wm/overview/overview_grid_unittest.cc b/ash/wm/overview/overview_grid_unittest.cc
index c6ea4e1..bbba7e9 100644
--- a/ash/wm/overview/overview_grid_unittest.cc
+++ b/ash/wm/overview/overview_grid_unittest.cc
@@ -149,7 +149,8 @@
   // window. So the first window will not animate.
   auto window1 = CreateTestWindow(gfx::Rect(100, 100));
   auto window2 = CreateTestWindow(gfx::Rect(400, 400));
-  window2->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  window2->SetProperty(aura::client::kZOrderingKey,
+                       ui::ZOrderLevel::kFloatingWindow);
   std::vector<gfx::RectF> target_bounds = {gfx::RectF(100.f, 100.f),
                                            gfx::RectF(100.f, 100.f)};
   CheckAnimationStates({window1.get(), window2.get()}, target_bounds,
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 4a80f21..5510247 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -2181,8 +2181,10 @@
   std::unique_ptr<aura::Window> window6(CreateTestWindow(bounds));
   std::unique_ptr<aura::Window> window7(CreateTestWindow(bounds));
   std::unique_ptr<aura::Window> window8(CreateTestWindow(bounds));
-  window3->SetProperty(aura::client::kAlwaysOnTopKey, true);
-  window5->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  window3->SetProperty(aura::client::kZOrderingKey,
+                       ui::ZOrderLevel::kFloatingWindow);
+  window5->SetProperty(aura::client::kZOrderingKey,
+                       ui::ZOrderLevel::kFloatingWindow);
 
   // Control z order and MRU order.
   ::wm::ActivateWindow(window8.get());
diff --git a/ash/wm/overview/rounded_label_widget.cc b/ash/wm/overview/rounded_label_widget.cc
index 0b851b0..f8b3f5b 100644
--- a/ash/wm/overview/rounded_label_widget.cc
+++ b/ash/wm/overview/rounded_label_widget.cc
@@ -79,7 +79,6 @@
   views::Widget::InitParams widget_params;
   widget_params.name = params.name;
   widget_params.type = views::Widget::InitParams::TYPE_POPUP;
-  widget_params.keep_on_top = false;
   widget_params.ownership =
       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   widget_params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
diff --git a/ash/wm/pip/pip_window_resizer_unittest.cc b/ash/wm/pip/pip_window_resizer_unittest.cc
index 28165922..c9157c3 100644
--- a/ash/wm/pip/pip_window_resizer_unittest.cc
+++ b/ash/wm/pip/pip_window_resizer_unittest.cc
@@ -117,7 +117,7 @@
     views::Widget::InitParams params;
     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
     params.bounds = screen_bounds;
-    params.keep_on_top = true;
+    params.z_order = ui::ZOrderLevel::kFloatingWindow;
     params.context = root_window;
     widget->Init(params);
     widget->Show();
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index f3e577f..385c354 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -597,11 +597,13 @@
   EXPECT_TRUE(!split_view_divider());
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   EXPECT_TRUE(split_view_divider());
-  EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop());
+  EXPECT_NE(ui::ZOrderLevel::kNormal,
+            split_view_divider()->divider_widget()->GetZOrderLevel());
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
   EXPECT_TRUE(split_view_divider());
-  EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop());
+  EXPECT_NE(ui::ZOrderLevel::kNormal,
+            split_view_divider()->divider_widget()->GetZOrderLevel());
 
   // Test that activating an non-snappable window ends the split view mode.
   std::unique_ptr<aura::Window> window3(CreateNonSnappableWindow(bounds));
@@ -2132,7 +2134,8 @@
 TEST_F(SplitViewControllerTest, AlwaysOnTopWindow) {
   const gfx::Rect bounds(0, 0, 400, 400);
   std::unique_ptr<aura::Window> always_on_top_window(CreateWindow(bounds));
-  always_on_top_window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  always_on_top_window->SetProperty(aura::client::kZOrderingKey,
+                                    ui::ZOrderLevel::kFloatingWindow);
   std::unique_ptr<aura::Window> normal_window(CreateWindow(bounds));
 
   split_view_controller()->SnapWindow(always_on_top_window.get(),
@@ -2140,15 +2143,18 @@
   split_view_controller()->SnapWindow(normal_window.get(),
                                       SplitViewController::RIGHT);
   EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
-  EXPECT_TRUE(always_on_top_window->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window->GetProperty(aura::client::kZOrderingKey));
 
   wm::ActivateWindow(always_on_top_window.get());
   EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
-  EXPECT_TRUE(always_on_top_window->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window->GetProperty(aura::client::kZOrderingKey));
 
   wm::ActivateWindow(normal_window.get());
   EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
-  EXPECT_TRUE(always_on_top_window->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window->GetProperty(aura::client::kZOrderingKey));
 }
 
 // Test that pinning a window ends split view mode.
@@ -2708,18 +2714,18 @@
                                       SplitViewController::RIGHT);
   views::Widget* split_divider_widget =
       split_view_controller()->split_view_divider()->divider_widget();
-  EXPECT_TRUE(split_divider_widget->IsAlwaysOnTop());
+  EXPECT_NE(ui::ZOrderLevel::kNormal, split_divider_widget->GetZOrderLevel());
 
   std::unique_ptr<WindowResizer> resizer =
       StartDrag(window1.get(), window1.get());
   ASSERT_TRUE(resizer.get());
-  EXPECT_FALSE(split_divider_widget->IsAlwaysOnTop());
+  EXPECT_EQ(ui::ZOrderLevel::kNormal, split_divider_widget->GetZOrderLevel());
 
   resizer->Drag(gfx::Point(), 0);
-  EXPECT_FALSE(split_divider_widget->IsAlwaysOnTop());
+  EXPECT_EQ(ui::ZOrderLevel::kNormal, split_divider_widget->GetZOrderLevel());
 
   CompleteDrag(std::move(resizer));
-  EXPECT_TRUE(split_divider_widget->IsAlwaysOnTop());
+  EXPECT_NE(ui::ZOrderLevel::kNormal, split_divider_widget->GetZOrderLevel());
 }
 
 // Test the functionalities that are related to dragging a maximized window's
@@ -4071,7 +4077,8 @@
 
   EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
-  EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop());
+  EXPECT_NE(ui::ZOrderLevel::kNormal,
+            split_view_divider()->divider_widget()->GetZOrderLevel());
 }
 
 // Tests that the divider bar should be placed on top after the drag ends, no
@@ -4094,7 +4101,8 @@
   DragWindowWithOffset(resizer.get(), 10, 10);
   CompleteDrag(std::move(resizer));
   EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
-  EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop());
+  EXPECT_NE(ui::ZOrderLevel::kNormal,
+            split_view_divider()->divider_widget()->GetZOrderLevel());
 
   // If the dragged window is destroyed after drag ends:
   resizer = StartDrag(dragged_window.get(), dragged_window.get());
@@ -4104,7 +4112,8 @@
   dragged_window.reset();
   EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
-  EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop());
+  EXPECT_NE(ui::ZOrderLevel::kNormal,
+            split_view_divider()->divider_widget()->GetZOrderLevel());
 }
 
 TEST_F(SplitViewTabDraggingTest, IgnoreActivatedTabDraggingWindow) {
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc
index 73ac1b5..30ef609 100644
--- a/ash/wm/splitview/split_view_divider.cc
+++ b/ash/wm/splitview/split_view_divider.cc
@@ -454,7 +454,7 @@
 
 void SplitViewDivider::SetAlwaysOnTop(bool on_top) {
   if (on_top) {
-    divider_widget_->SetAlwaysOnTop(true);
+    divider_widget_->SetZOrderLevel(ui::ZOrderLevel::kFloatingUIElement);
 
     // Special handling when put divider into always_on_top container. We want
     // to put it at the bottom so it won't block other always_on_top windows.
@@ -464,7 +464,7 @@
     always_on_top_container->StackChildAtBottom(
         divider_widget_->GetNativeWindow());
   } else {
-    divider_widget_->SetAlwaysOnTop(false);
+    divider_widget_->SetZOrderLevel(ui::ZOrderLevel::kNormal);
   }
 }
 
diff --git a/ash/wm/splitview/split_view_drag_indicators.cc b/ash/wm/splitview/split_view_drag_indicators.cc
index c3a7c18f..0e79125 100644
--- a/ash/wm/splitview/split_view_drag_indicators.cc
+++ b/ash/wm/splitview/split_view_drag_indicators.cc
@@ -43,7 +43,6 @@
   auto widget = std::make_unique<views::Widget>();
   views::Widget::InitParams params;
   params.type = views::Widget::InitParams::TYPE_POPUP;
-  params.keep_on_top = false;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.accept_events = false;
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
index 423ce7a..78a4b3c 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -445,9 +445,10 @@
 void TabletModeWindowManager::OnWindowPropertyChanged(aura::Window* window,
                                                       const void* key,
                                                       intptr_t old) {
-  // Stop managing |window| if the always-on-top property is added.
-  if (key == aura::client::kAlwaysOnTopKey &&
-      window->GetProperty(aura::client::kAlwaysOnTopKey)) {
+  // Stop managing |window| if it is moved to have a non-normal z-order.
+  if (key == aura::client::kZOrderingKey &&
+      window->GetProperty(aura::client::kZOrderingKey) !=
+          ui::ZOrderLevel::kNormal) {
     ForgetWindow(window, false /* destroyed */);
   }
 }
@@ -693,10 +694,12 @@
 bool TabletModeWindowManager::ShouldHandleWindow(aura::Window* window) {
   DCHECK(window);
 
-  // Windows with the always-on-top property should be free-floating and thus
+  // Windows that don't have normal z-ordering should be free-floating and thus
   // not managed by us.
-  if (window->GetProperty(aura::client::kAlwaysOnTopKey))
+  if (window->GetProperty(aura::client::kZOrderingKey) !=
+      ui::ZOrderLevel::kNormal) {
     return false;
+  }
 
   // If the changing bounds in the maximized/fullscreen is allowed, then
   // let the client manage it even in tablet mode.
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
index a2845048..ca1e6243 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -1529,8 +1529,10 @@
       CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect1));
   std::unique_ptr<aura::Window> w2(CreateFixedSizeNonMaximizableWindow(
       aura::client::WINDOW_TYPE_NORMAL, rect2));
-  w1->SetProperty(aura::client::kAlwaysOnTopKey, true);
-  w2->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  w1->SetProperty(aura::client::kZOrderingKey,
+                  ui::ZOrderLevel::kFloatingWindow);
+  w2->SetProperty(aura::client::kZOrderingKey,
+                  ui::ZOrderLevel::kFloatingWindow);
   EXPECT_FALSE(wm::GetWindowState(w1.get())->IsMaximized());
   EXPECT_FALSE(wm::GetWindowState(w2.get())->IsMaximized());
   EXPECT_EQ(rect1.ToString(), w1->bounds().ToString());
@@ -1550,8 +1552,8 @@
   // Remove the always-on-top property from both windows while in maximize
   // mode. The windows should become managed, which means they should be
   // maximized/centered and no longer be draggable.
-  w1->SetProperty(aura::client::kAlwaysOnTopKey, false);
-  w2->SetProperty(aura::client::kAlwaysOnTopKey, false);
+  w1->SetProperty(aura::client::kZOrderingKey, ui::ZOrderLevel::kNormal);
+  w2->SetProperty(aura::client::kZOrderingKey, ui::ZOrderLevel::kNormal);
   EXPECT_EQ(2, manager->GetNumberOfManagedWindows());
   EXPECT_TRUE(wm::GetWindowState(w1.get())->IsMaximized());
   EXPECT_FALSE(wm::GetWindowState(w2.get())->IsMaximized());
@@ -1563,8 +1565,10 @@
   // Applying the always-on-top property to both windows while in maximize
   // mode should cause both windows to return to their original size,
   // position, and state.
-  w1->SetProperty(aura::client::kAlwaysOnTopKey, true);
-  w2->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  w1->SetProperty(aura::client::kZOrderingKey,
+                  ui::ZOrderLevel::kFloatingWindow);
+  w2->SetProperty(aura::client::kZOrderingKey,
+                  ui::ZOrderLevel::kFloatingWindow);
   EXPECT_EQ(0, manager->GetNumberOfManagedWindows());
   EXPECT_FALSE(wm::GetWindowState(w1.get())->IsMaximized());
   EXPECT_FALSE(wm::GetWindowState(w2.get())->IsMaximized());
@@ -1728,7 +1732,8 @@
   params.show_on_creation = false;
   std::unique_ptr<aura::Window> window(CreateWindowInWatchedContainer(params));
   wm::GetWindowState(window.get())->set_allow_set_bounds_direct(true);
-  window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  window->SetProperty(aura::client::kZOrderingKey,
+                      ui::ZOrderLevel::kFloatingWindow);
   window->Show();
 }
 
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 07b226c2..2f4e9f55 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -326,8 +326,9 @@
   }
 }
 
-void WindowState::DisableAlwaysOnTop(aura::Window* window_on_top) {
-  if (GetAlwaysOnTop() && !IsPip()) {
+void WindowState::DisableZOrdering(aura::Window* window_on_top) {
+  ui::ZOrderLevel z_order = GetZOrdering();
+  if (z_order != ui::ZOrderLevel::kNormal && !IsPip()) {
     // |window_| is hidden first to avoid canceling fullscreen mode when it is
     // no longer always on top and gets added to default container. This avoids
     // sending redundant OnFullscreenStateChanged to the layout manager. The
@@ -336,7 +337,7 @@
     bool visible = window_->IsVisible();
     if (visible)
       window_->Hide();
-    window_->SetProperty(aura::client::kAlwaysOnTopKey, false);
+    window_->SetProperty(aura::client::kZOrderingKey, ui::ZOrderLevel::kNormal);
     // Technically it is possible that a |window_| could make itself
     // always_on_top really quickly. This is probably not a realistic case but
     // check if the two windows are in the same container just in case.
@@ -344,14 +345,14 @@
       window_->parent()->StackChildAbove(window_on_top, window_);
     if (visible)
       window_->Show();
-    cached_always_on_top_ = true;
+    cached_z_order_ = z_order;
   }
 }
 
-void WindowState::RestoreAlwaysOnTop() {
-  if (cached_always_on_top_) {
-    cached_always_on_top_ = false;
-    window_->SetProperty(aura::client::kAlwaysOnTopKey, true);
+void WindowState::RestoreZOrdering() {
+  if (cached_z_order_ != ui::ZOrderLevel::kNormal) {
+    window_->SetProperty(aura::client::kZOrderingKey, cached_z_order_);
+    cached_z_order_ = ui::ZOrderLevel::kNormal;
   }
 }
 
@@ -544,15 +545,15 @@
       unminimize_to_restore_bounds_(false),
       hide_shelf_when_fullscreen_(true),
       autohide_shelf_when_maximized_or_fullscreen_(false),
-      cached_always_on_top_(false),
+      cached_z_order_(ui::ZOrderLevel::kNormal),
       ignore_property_change_(false),
       current_state_(new DefaultState(ToWindowStateType(GetShowState()))) {
   window_->AddObserver(this);
   OnPrePipStateChange(WindowStateType::kDefault);
 }
 
-bool WindowState::GetAlwaysOnTop() const {
-  return window_->GetProperty(aura::client::kAlwaysOnTopKey);
+ui::ZOrderLevel WindowState::GetZOrdering() const {
+  return window_->GetProperty(aura::client::kZOrderingKey);
 }
 
 ui::WindowShowState WindowState::GetShowState() const {
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index 0d753828..1f376ef 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -174,12 +174,12 @@
   // TODO(oshima): Change to use RESTORE event.
   void Restore();
 
-  // Caches, then disables always on top state and then stacks |window_| below
-  // |window_on_top| if a |window_| is currently in always on top state.
-  void DisableAlwaysOnTop(aura::Window* window_on_top);
+  // Caches, then disables z-ordering state and then stacks |window_| below
+  // |window_on_top| if |window_| currently has a special z-order.
+  void DisableZOrdering(aura::Window* window_on_top);
 
-  // Restores always on top state that a window might have cached.
-  void RestoreAlwaysOnTop();
+  // Restores the z-ordering state that a window might have cached.
+  void RestoreZOrdering();
 
   // Invoked when a WMevent occurs, which drives the internal
   // state machine.
@@ -376,8 +376,8 @@
 
   bool HasMaximumWidthOrHeight() const;
 
-  // Returns the window's current always_on_top state.
-  bool GetAlwaysOnTop() const;
+  // Returns the window's current z-ordering state.
+  ui::ZOrderLevel GetZOrdering() const;
 
   // Returns the window's current show state.
   ui::WindowShowState GetShowState() const;
@@ -451,7 +451,7 @@
   bool ignore_keyboard_bounds_change_ = false;
   bool hide_shelf_when_fullscreen_;
   bool autohide_shelf_when_maximized_or_fullscreen_;
-  bool cached_always_on_top_;
+  ui::ZOrderLevel cached_z_order_;
   bool allow_set_bounds_direct_ = false;
 
   // A property to save the ratio between snapped window width and display
diff --git a/ash/wm/workspace/phantom_window_controller.cc b/ash/wm/workspace/phantom_window_controller.cc
index 2ccf65a..59922fe 100644
--- a/ash/wm/workspace/phantom_window_controller.cc
+++ b/ash/wm/workspace/phantom_window_controller.cc
@@ -73,7 +73,7 @@
   // PhantomWindowController is used by FrameMaximizeButton to highlight the
   // launcher button. Put the phantom in the same window as the launcher so that
   // the phantom is visible.
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.name = "PhantomWindow";
   params.layer_type = ui::LAYER_SOLID_COLOR;
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index 8ed01ff..99cc601 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -152,7 +152,7 @@
   backdrop_controller_->OnWindowAddedToLayout();
   WindowPositioner::RearrangeVisibleWindowOnShow(child);
   if (Shell::Get()->screen_pinning_controller()->IsPinned())
-    wm::GetWindowState(child)->DisableAlwaysOnTop(nullptr);
+    wm::GetWindowState(child)->DisableZOrdering(nullptr);
 }
 
 void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
@@ -302,8 +302,9 @@
 void WorkspaceLayoutManager::OnWindowPropertyChanged(aura::Window* window,
                                                      const void* key,
                                                      intptr_t old) {
-  if (key == aura::client::kAlwaysOnTopKey) {
-    if (window->GetProperty(aura::client::kAlwaysOnTopKey)) {
+  if (key == aura::client::kZOrderingKey) {
+    if (window->GetProperty(aura::client::kZOrderingKey) !=
+        ui::ZOrderLevel::kNormal) {
       aura::Window* container =
           root_window_controller_->always_on_top_controller()->GetContainer(
               window);
@@ -519,9 +520,9 @@
   for (aura::Window* window : windows) {
     wm::WindowState* window_state = wm::GetWindowState(window);
     if (active_desk_fullscreen_window)
-      window_state->DisableAlwaysOnTop(active_desk_fullscreen_window);
+      window_state->DisableZOrdering(active_desk_fullscreen_window);
     else
-      window_state->RestoreAlwaysOnTop();
+      window_state->RestoreZOrdering();
   }
 }
 
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index ea208b0a..3790e7db 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -808,34 +808,37 @@
       CreateTestWindowInShellWithBounds(bounds));
   std::unique_ptr<aura::Window> always_on_top_window2(
       CreateTestWindowInShellWithBounds(bounds));
-  always_on_top_window1->SetProperty(aura::client::kAlwaysOnTopKey, true);
-  always_on_top_window2->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  always_on_top_window1->SetProperty(aura::client::kZOrderingKey,
+                                     ui::ZOrderLevel::kFloatingWindow);
+  always_on_top_window2->SetProperty(aura::client::kZOrderingKey,
+                                     ui::ZOrderLevel::kFloatingWindow);
   // Making a window fullscreen temporarily suspends always on top state.
   fullscreen_window->SetProperty(aura::client::kShowStateKey,
                                  ui::SHOW_STATE_FULLSCREEN);
-  EXPECT_FALSE(
-      always_on_top_window1->GetProperty(aura::client::kAlwaysOnTopKey));
-  EXPECT_FALSE(
-      always_on_top_window2->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kNormal,
+            always_on_top_window1->GetProperty(aura::client::kZOrderingKey));
+  EXPECT_EQ(ui::ZOrderLevel::kNormal,
+            always_on_top_window2->GetProperty(aura::client::kZOrderingKey));
   EXPECT_NE(nullptr,
             wm::GetWindowForFullscreenModeForContext(fullscreen_window.get()));
 
   // Adding a new always-on-top window is not affected by fullscreen.
   std::unique_ptr<aura::Window> always_on_top_window3(
       CreateTestWindowInShellWithBounds(bounds));
-  always_on_top_window3->SetProperty(aura::client::kAlwaysOnTopKey, true);
-  EXPECT_TRUE(
-      always_on_top_window3->GetProperty(aura::client::kAlwaysOnTopKey));
+  always_on_top_window3->SetProperty(aura::client::kZOrderingKey,
+                                     ui::ZOrderLevel::kFloatingWindow);
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window3->GetProperty(aura::client::kZOrderingKey));
 
   // Making fullscreen window normal restores always on top windows.
   fullscreen_window->SetProperty(aura::client::kShowStateKey,
                                  ui::SHOW_STATE_NORMAL);
-  EXPECT_TRUE(
-      always_on_top_window1->GetProperty(aura::client::kAlwaysOnTopKey));
-  EXPECT_TRUE(
-      always_on_top_window2->GetProperty(aura::client::kAlwaysOnTopKey));
-  EXPECT_TRUE(
-      always_on_top_window3->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window1->GetProperty(aura::client::kZOrderingKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window2->GetProperty(aura::client::kZOrderingKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window3->GetProperty(aura::client::kZOrderingKey));
   EXPECT_EQ(nullptr,
             wm::GetWindowForFullscreenModeForContext(fullscreen_window.get()));
 }
@@ -851,22 +854,26 @@
   wm::WindowState* window_state = wm::GetWindowState(pip_window.get());
   const wm::WMEvent enter_pip(wm::WM_EVENT_PIP);
   window_state->OnWMEvent(&enter_pip);
-  pip_window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  pip_window->SetProperty(aura::client::kZOrderingKey,
+                          ui::ZOrderLevel::kFloatingWindow);
   EXPECT_TRUE(window_state->IsPip());
-  EXPECT_TRUE(pip_window->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            pip_window->GetProperty(aura::client::kZOrderingKey));
 
   // Making a window fullscreen temporarily suspends always on top state, but
   // should not do so for PIP.
   fullscreen_window->SetProperty(aura::client::kShowStateKey,
                                  ui::SHOW_STATE_FULLSCREEN);
-  EXPECT_TRUE(pip_window->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            pip_window->GetProperty(aura::client::kZOrderingKey));
   EXPECT_NE(nullptr,
             wm::GetWindowForFullscreenModeForContext(fullscreen_window.get()));
 
   // Making fullscreen window normal does not affect PIP.
   fullscreen_window->SetProperty(aura::client::kShowStateKey,
                                  ui::SHOW_STATE_NORMAL);
-  EXPECT_TRUE(pip_window->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            pip_window->GetProperty(aura::client::kZOrderingKey));
   EXPECT_EQ(nullptr,
             wm::GetWindowForFullscreenModeForContext(fullscreen_window.get()));
 }
@@ -880,32 +887,35 @@
       CreateTestWindowInShellWithBounds(bounds));
   std::unique_ptr<aura::Window> always_on_top_window2(
       CreateTestWindowInShellWithBounds(bounds));
-  always_on_top_window1->SetProperty(aura::client::kAlwaysOnTopKey, true);
-  always_on_top_window2->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  always_on_top_window1->SetProperty(aura::client::kZOrderingKey,
+                                     ui::ZOrderLevel::kFloatingWindow);
+  always_on_top_window2->SetProperty(aura::client::kZOrderingKey,
+                                     ui::ZOrderLevel::kFloatingWindow);
 
   // Making a window pinned temporarily suspends always on top state.
   const bool trusted = false;
   wm::PinWindow(pinned_window.get(), trusted);
-  EXPECT_FALSE(
-      always_on_top_window1->GetProperty(aura::client::kAlwaysOnTopKey));
-  EXPECT_FALSE(
-      always_on_top_window2->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kNormal,
+            always_on_top_window1->GetProperty(aura::client::kZOrderingKey));
+  EXPECT_EQ(ui::ZOrderLevel::kNormal,
+            always_on_top_window2->GetProperty(aura::client::kZOrderingKey));
 
   // Adding a new always-on-top window also is affected by pinned mode.
   std::unique_ptr<aura::Window> always_on_top_window3(
       CreateTestWindowInShellWithBounds(bounds));
-  always_on_top_window3->SetProperty(aura::client::kAlwaysOnTopKey, true);
-  EXPECT_FALSE(
-      always_on_top_window3->GetProperty(aura::client::kAlwaysOnTopKey));
+  always_on_top_window3->SetProperty(aura::client::kZOrderingKey,
+                                     ui::ZOrderLevel::kFloatingWindow);
+  EXPECT_EQ(ui::ZOrderLevel::kNormal,
+            always_on_top_window3->GetProperty(aura::client::kZOrderingKey));
 
   // Making pinned window normal restores always on top windows.
   wm::GetWindowState(pinned_window.get())->Restore();
-  EXPECT_TRUE(
-      always_on_top_window1->GetProperty(aura::client::kAlwaysOnTopKey));
-  EXPECT_TRUE(
-      always_on_top_window2->GetProperty(aura::client::kAlwaysOnTopKey));
-  EXPECT_TRUE(
-      always_on_top_window3->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window1->GetProperty(aura::client::kZOrderingKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window2->GetProperty(aura::client::kZOrderingKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            always_on_top_window3->GetProperty(aura::client::kZOrderingKey));
 }
 
 TEST_F(WorkspaceLayoutManagerSoloTest, PinnedDoesNotSuspendAlwaysOnTopForPip) {
@@ -918,16 +928,19 @@
     wm::WindowState* window_state = wm::GetWindowState(pip_window.get());
     const wm::WMEvent enter_pip(wm::WM_EVENT_PIP);
     window_state->OnWMEvent(&enter_pip);
-    pip_window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+    pip_window->SetProperty(aura::client::kZOrderingKey,
+                            ui::ZOrderLevel::kFloatingWindow);
     EXPECT_TRUE(window_state->IsPip());
-    EXPECT_TRUE(pip_window->GetProperty(aura::client::kAlwaysOnTopKey));
+    EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+              pip_window->GetProperty(aura::client::kZOrderingKey));
   }
 
   // Making a window pinned temporarily suspends always on top state, except
   // for PIP.
   const bool trusted = false;
   wm::PinWindow(pinned_window.get(), trusted);
-  EXPECT_TRUE(pip_window->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            pip_window->GetProperty(aura::client::kZOrderingKey));
 
   // Adding a new PIP window should still end up always on top.
   std::unique_ptr<aura::Window> pip_window2(
@@ -936,15 +949,19 @@
     wm::WindowState* window_state = wm::GetWindowState(pip_window2.get());
     const wm::WMEvent enter_pip(wm::WM_EVENT_PIP);
     window_state->OnWMEvent(&enter_pip);
-    pip_window2->SetProperty(aura::client::kAlwaysOnTopKey, true);
+    pip_window2->SetProperty(aura::client::kZOrderingKey,
+                             ui::ZOrderLevel::kFloatingWindow);
     EXPECT_TRUE(window_state->IsPip());
-    EXPECT_TRUE(pip_window2->GetProperty(aura::client::kAlwaysOnTopKey));
+    EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+              pip_window2->GetProperty(aura::client::kZOrderingKey));
   }
 
   // Making pinned window normal should not affect existing PIP windows.
   wm::GetWindowState(pinned_window.get())->Restore();
-  EXPECT_TRUE(pip_window->GetProperty(aura::client::kAlwaysOnTopKey));
-  EXPECT_TRUE(pip_window2->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            pip_window->GetProperty(aura::client::kZOrderingKey));
+  EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
+            pip_window2->GetProperty(aura::client::kZOrderingKey));
 }
 
 // Tests fullscreen window size during root window resize.
@@ -1058,7 +1075,8 @@
   std::unique_ptr<aura::Window> window(
       CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
   // window with AlwaysOnTop will be managed by BaseLayoutManager.
-  window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  window->SetProperty(aura::client::kZOrderingKey,
+                      ui::ZOrderLevel::kFloatingWindow);
   window->Show();
 
   Shelf* shelf = GetPrimaryShelf();
@@ -1999,7 +2017,8 @@
   std::unique_ptr<aura::Window> always_on_top_window(
       CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
   always_on_top_window->Show();
-  always_on_top_window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  always_on_top_window->SetProperty(aura::client::kZOrderingKey,
+                                    ui::ZOrderLevel::kFloatingWindow);
   always_on_top_window->SetProperty(kBackdropWindowMode,
                                     BackdropWindowMode::kEnabled);
 
@@ -2009,7 +2028,8 @@
   // at this moment.
   ASSERT_EQ(always_on_top_container->children().size(), 2U);
 
-  always_on_top_window->SetProperty(aura::client::kAlwaysOnTopKey, false);
+  always_on_top_window->SetProperty(aura::client::kZOrderingKey,
+                                    ui::ZOrderLevel::kNormal);
   // The backdrop window will be destroyed immediately after
   // |always_on_top_window| moves to the default container.
   EXPECT_TRUE(always_on_top_container->children().empty());
diff --git a/base/android/proguard/chromium_apk.flags b/base/android/proguard/chromium_apk.flags
index 968bdb0..21995fe 100644
--- a/base/android/proguard/chromium_apk.flags
+++ b/base/android/proguard/chromium_apk.flags
@@ -15,6 +15,14 @@
   public static *** CREATOR;
 }
 
+# Keep all Fragment constructors since they are only usable via reflection.
+-keepclassmembers class * extends android.support.v4.app.Fragment {
+  public <init>();
+}
+-keepclassmembers class * extends androidx.fragment.app.Fragment {
+  public <init>();
+}
+
 # Don't obfuscate Parcelables as they might be marshalled outside Chrome.
 # If we annotated all Parcelables that get put into Bundles other than
 # for saveInstanceState (e.g. PendingIntents), then we could actually keep the
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc
index dbabc6d..e0352d0 100644
--- a/base/logging_unittest.cc
+++ b/base/logging_unittest.cc
@@ -38,15 +38,17 @@
 #include <fuchsia/logger/cpp/fidl.h>
 #include <fuchsia/logger/cpp/fidl_test_base.h>
 #include <lib/fidl/cpp/binding.h>
+#include <lib/zx/channel.h>
 #include <lib/zx/event.h>
-#include <lib/zx/port.h>
+#include <lib/zx/exception.h>
 #include <lib/zx/process.h>
 #include <lib/zx/thread.h>
 #include <lib/zx/time.h>
 #include <zircon/process.h>
 #include <zircon/syscalls/debug.h>
-#include <zircon/syscalls/port.h>
+#include <zircon/syscalls/exception.h>
 #include <zircon/types.h>
+
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/fuchsia/service_directory_client.h"
 #endif  // OS_FUCHSIA
@@ -332,31 +334,33 @@
   }
 #endif
 
-static const unsigned int kExceptionPortKey = 1u;
-static const unsigned int kThreadEndedPortKey = 2u;
-
 struct thread_data_t {
   // For signaling the thread ended properly.
-  zx::unowned_event event;
-  // For registering thread termination.
-  zx::unowned_port port;
+  zx::event event;
+  // For catching thread exceptions. Created by the crashing thread.
+  zx::channel channel;
   // Location where the thread is expected to crash.
   int death_location;
 };
 
-void* CrashThread(void* arg) {
-  zx_status_t status;
+// Indicates the exception channel has been created successfully.
+constexpr zx_signals_t kChannelReadySignal = ZX_USER_SIGNAL_0;
 
+// Indicates an error setting up the crash thread.
+constexpr zx_signals_t kCrashThreadErrorSignal = ZX_USER_SIGNAL_1;
+
+void* CrashThread(void* arg) {
   thread_data_t* data = (thread_data_t*)arg;
   int death_location = data->death_location;
 
-  // Register the exception handler on the port.
-  status = zx::thread::self()->bind_exception_port(*data->port,
-                                                   kExceptionPortKey, 0);
+  // Register the exception handler.
+  zx_status_t status =
+      zx::thread::self()->create_exception_channel(0, &data->channel);
   if (status != ZX_OK) {
-    data->event->signal(0, ZX_USER_SIGNAL_0);
+    data->event.signal(0, kCrashThreadErrorSignal);
     return nullptr;
   }
+  data->event.signal(0, kChannelReadySignal);
 
   DO_CHECK(death_location != 1);
   DO_CHECK(death_location != 2);
@@ -364,44 +368,48 @@
 
   // We should never reach this point, signal the thread incorrectly ended
   // properly.
-  data->event->signal(0, ZX_USER_SIGNAL_0);
+  data->event.signal(0, kCrashThreadErrorSignal);
   return nullptr;
 }
 
 // Runs the CrashThread function in a separate thread.
 void SpawnCrashThread(int death_location, uintptr_t* child_crash_addr) {
-  zx::port port;
   zx::event event;
-  zx_status_t status;
-
-  status = zx::port::create(0, &port);
-  ASSERT_EQ(status, ZX_OK);
-  status = zx::event::create(0, &event);
-  ASSERT_EQ(status, ZX_OK);
-
-  // Register the thread ended event on the port.
-  status = event.wait_async(port, kThreadEndedPortKey, ZX_USER_SIGNAL_0,
-                            ZX_WAIT_ASYNC_ONCE);
+  zx_status_t status = zx::event::create(0, &event);
   ASSERT_EQ(status, ZX_OK);
 
   // Run the thread.
-  thread_data_t thread_data = {zx::unowned_event(event), zx::unowned_port(port),
-                               death_location};
+  thread_data_t thread_data = {std::move(event), zx::channel(), death_location};
   pthread_t thread;
   int ret = pthread_create(&thread, nullptr, CrashThread, &thread_data);
   ASSERT_EQ(ret, 0);
 
-  // Wait on the port.
-  zx_port_packet_t packet;
-  status = port.wait(zx::time::infinite(), &packet);
+  // Wait for the thread to set up its exception channel.
+  zx_signals_t signals = 0;
+  status =
+      thread_data.event.wait_one(kChannelReadySignal | kCrashThreadErrorSignal,
+                                 zx::time::infinite(), &signals);
+  ASSERT_EQ(status, ZX_OK);
+  ASSERT_EQ(signals, kChannelReadySignal);
+
+  // Wait for the exception and read it out of the channel.
+  status =
+      thread_data.channel.wait_one(ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED,
+                                   zx::time::infinite(), &signals);
   ASSERT_EQ(status, ZX_OK);
   // Check the thread did crash and not terminate.
-  ASSERT_EQ(packet.key, kExceptionPortKey);
+  ASSERT_FALSE(signals & ZX_CHANNEL_PEER_CLOSED);
+
+  zx_exception_info_t exception_info;
+  zx::exception exception;
+  status = thread_data.channel.read(
+      0, &exception_info, exception.reset_and_get_address(),
+      sizeof(exception_info), 1, nullptr, nullptr);
+  ASSERT_EQ(status, ZX_OK);
 
   // Get the crash address.
   zx::thread zircon_thread;
-  status = zx::process::self()->get_child(packet.exception.tid,
-                                          ZX_RIGHT_SAME_RIGHTS, &zircon_thread);
+  status = exception.get_thread(&zircon_thread);
   ASSERT_EQ(status, ZX_OK);
   zx_thread_state_general_regs_t buffer;
   status = zircon_thread.read_state(ZX_THREAD_STATE_GENERAL_REGS, &buffer,
diff --git a/base/memory/platform_shared_memory_region.h b/base/memory/platform_shared_memory_region.h
index 1a59564..a04b44a 100644
--- a/base/memory/platform_shared_memory_region.h
+++ b/base/memory/platform_shared_memory_region.h
@@ -115,7 +115,11 @@
     CREATE_FILE_MAPPING_FAILURE = 6,
     REDUCE_PERMISSIONS_FAILURE = 7,
     ALREADY_EXISTS = 8,
-    kMaxValue = ALREADY_EXISTS
+    ALLOCATE_FILE_REGION_FAILURE = 9,
+    FSTAT_FAILURE = 10,
+    INODES_MISMATCH = 11,
+    GET_SHMEM_TEMP_DIR_FAILURE = 12,
+    kMaxValue = GET_SHMEM_TEMP_DIR_FAILURE
   };
 
 #if defined(OS_LINUX)
diff --git a/base/memory/platform_shared_memory_region_posix.cc b/base/memory/platform_shared_memory_region_posix.cc
index 036c6e5..1fe6f81 100644
--- a/base/memory/platform_shared_memory_region_posix.cc
+++ b/base/memory/platform_shared_memory_region_posix.cc
@@ -10,6 +10,7 @@
 
 #include "base/files/file.h"
 #include "base/files/file_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 
@@ -18,6 +19,12 @@
 
 namespace {
 
+#if !defined(OS_NACL)
+void LogCreateError(PlatformSharedMemoryRegion::CreateError error) {
+  UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error);
+}
+#endif
+
 struct ScopedPathUnlinkerTraits {
   static const FilePath* InvalidValue() { return nullptr; }
 
@@ -226,11 +233,15 @@
   // Untrusted code can't create descriptors or handles.
   return {};
 #else
-  if (size == 0)
+  if (size == 0) {
+    LogCreateError(PlatformSharedMemoryRegion::CreateError::SIZE_ZERO);
     return {};
+  }
 
-  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max())) {
+    LogCreateError(PlatformSharedMemoryRegion::CreateError::SIZE_TOO_LARGE);
     return {};
+  }
 
   CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
                                      "lead to this region being non-modifiable";
@@ -249,13 +260,18 @@
 #else
           false /* executable */,
 #endif
-          &directory))
+          &directory)) {
+    LogCreateError(
+        PlatformSharedMemoryRegion::CreateError::GET_SHMEM_TEMP_DIR_FAILURE);
     return {};
+  }
 
   FilePath path;
   File shm_file(CreateAndOpenFdForTemporaryFileInDir(directory, &path));
 
   if (!shm_file.IsValid()) {
+    LogCreateError(
+        PlatformSharedMemoryRegion::CreateError::CREATE_FILE_MAPPING_FAILURE);
     PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
     FilePath dir = path.DirName();
     if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
@@ -278,34 +294,43 @@
     // Also open as readonly so that we can ConvertToReadOnly().
     readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
     if (!readonly_fd.is_valid()) {
+      LogCreateError(
+          PlatformSharedMemoryRegion::CreateError::REDUCE_PERMISSIONS_FAILURE);
       DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
       return {};
     }
   }
 
-  if (!AllocateFileRegion(&shm_file, 0, size))
+  if (!AllocateFileRegion(&shm_file, 0, size)) {
+    LogCreateError(
+        PlatformSharedMemoryRegion::CreateError::ALLOCATE_FILE_REGION_FAILURE);
     return {};
+  }
 
   if (readonly_fd.is_valid()) {
     struct stat stat = {};
     if (fstat(shm_file.GetPlatformFile(), &stat) != 0) {
+      LogCreateError(PlatformSharedMemoryRegion::CreateError::FSTAT_FAILURE);
       DPLOG(ERROR) << "fstat(fd) failed";
       return {};
     }
 
     struct stat readonly_stat = {};
     if (fstat(readonly_fd.get(), &readonly_stat) != 0) {
+      LogCreateError(PlatformSharedMemoryRegion::CreateError::FSTAT_FAILURE);
       DPLOG(ERROR) << "fstat(readonly_fd) failed";
       return {};
     }
 
     if (stat.st_dev != readonly_stat.st_dev ||
         stat.st_ino != readonly_stat.st_ino) {
+      LogCreateError(PlatformSharedMemoryRegion::CreateError::INODES_MISMATCH);
       LOG(ERROR) << "Writable and read-only inodes don't match; bailing";
       return {};
     }
   }
 
+  LogCreateError(PlatformSharedMemoryRegion::CreateError::SUCCESS);
   return PlatformSharedMemoryRegion(
       {ScopedFD(shm_file.TakePlatformFile()), std::move(readonly_fd)}, mode,
       size, UnguessableToken::Create());
diff --git a/base/message_loop/message_loop_current.cc b/base/message_loop/message_loop_current.cc
index 71a45d0..54e2d2b 100644
--- a/base/message_loop/message_loop_current.cc
+++ b/base/message_loop/message_loop_current.cc
@@ -51,11 +51,6 @@
   current_->RemoveDestructionObserver(destruction_observer);
 }
 
-scoped_refptr<SingleThreadTaskRunner> MessageLoopCurrent::task_runner() const {
-  DCHECK(current_->IsBoundToCurrentThread());
-  return current_->GetTaskRunner();
-}
-
 void MessageLoopCurrent::SetTaskRunner(
     scoped_refptr<SingleThreadTaskRunner> task_runner) {
   DCHECK(current_->IsBoundToCurrentThread());
diff --git a/base/message_loop/message_loop_current.h b/base/message_loop/message_loop_current.h
index f259d89..08a1c5e 100644
--- a/base/message_loop/message_loop_current.h
+++ b/base/message_loop/message_loop_current.h
@@ -105,11 +105,6 @@
   // DestructionObserver is receiving a notification callback.
   void RemoveDestructionObserver(DestructionObserver* destruction_observer);
 
-  // Forwards to MessageLoop::task_runner().
-  // DEPRECATED(https://crbug.com/616447): Use ThreadTaskRunnerHandle::Get()
-  // instead of MessageLoopCurrent::Get()->task_runner().
-  scoped_refptr<SingleThreadTaskRunner> task_runner() const;
-
   // Forwards to MessageLoop::SetTaskRunner().
   // DEPRECATED(https://crbug.com/825327): only owners of the MessageLoop
   // instance should replace its TaskRunner.
diff --git a/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc b/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc
index ac3b966..f143ed8 100644
--- a/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc
+++ b/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/message_loop/message_loop_current.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/test/test_pending_task.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -24,7 +25,7 @@
 namespace {
 
 TaskRunner* GetCurrentTaskRunner() {
-  return MessageLoopCurrent::Get()->task_runner().get();
+  return ThreadTaskRunnerHandle::Get().get();
 }
 
 void AssignTrue(bool* out) {
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py
index b050a8e..6437758 100755
--- a/build/chromeos/test_runner.py
+++ b/build/chromeos/test_runner.py
@@ -564,9 +564,9 @@
               '--gtest_repeat')]
 
     if self._additional_args:
-      raise TestFormatError(
-          'Sanity test should not have additional args: %s' % (
-              self._additional_args))
+      logging.error(
+          'Sanity test should not have additional args: These will be '
+          'ignored: %s', self._additional_args)
 
     # VMs don't have the disk space for an unstripped version of Chrome
     # instrumented for code coverage, so only strip in that case.
diff --git a/build/config/c++/libc++.natvis b/build/config/c++/libc++.natvis
index 0616088..2603e2e8 100644
--- a/build/config/c++/libc++.natvis
+++ b/build/config/c++/libc++.natvis
@@ -53,7 +53,9 @@
   <Type Name="std::__1::basic_string&lt;char,*&gt;">
     <!--<Intrinsic Name="is_long"
             Expression="((__rep*)&amp;__r_)-&gt;__s.__size_ &amp; 0x80" />-->
-    <!-- The above doesn't work for reasons I don't understand.
+    <!-- The above doesn't work because of https://llvm.org/PR41615
+         TODO(thakis): Now that we have clang r362038, try the above approach
+                       again.
          The below assumes the alternate string layout and little endianness :/
     -->
     <Intrinsic Name="is_long"
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index b240549..6b7e41b 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8907715714103854416
\ No newline at end of file
+8907684647168301152
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index dd61703..ab70073 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8907715712174591808
\ No newline at end of file
+8907684424932579328
\ No newline at end of file
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 5e55af1..4f2641cd 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -576,7 +576,6 @@
         "/DELAYLOAD:dxgi.dll",
         "/DELAYLOAD:dxva2.dll",
         "/DELAYLOAD:esent.dll",
-        "/DELAYLOAD:gdi32.dll",
         "/DELAYLOAD:imm32.dll",
         "/DELAYLOAD:ole32.dll",
         "/DELAYLOAD:oleacc.dll",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 5b9f9cc..dbd1443 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -251,6 +251,7 @@
   "javatests/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerViewTest.java",
   "javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java",
   "javatests/src/org/chromium/chrome/browser/offlinepages/MHTMLPageTest.java",
+  "javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridgeTest.java",
   "javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageAutoFetchTest.java",
   "javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java",
   "javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java",
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/ArConsentDialog.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/ArConsentDialog.java
index 1a268a5..7f228eb 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/ArConsentDialog.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/ArConsentDialog.java
@@ -73,7 +73,7 @@
                                       .with(ModalDialogProperties.CANCEL_ON_TOUCH_OUTSIDE, true)
                                       .build();
         mModalDialogManager = activity.getModalDialogManager();
-        mModalDialogManager.showDialog(model, ModalDialogManager.ModalDialogType.APP);
+        mModalDialogManager.showDialog(model, ModalDialogManager.ModalDialogType.TAB);
     }
 
     @Override
@@ -142,6 +142,6 @@
 
     @NativeMethods
     /* package */ interface Natives {
-        void onUserConsentResult(long nativeArcoreConsentPrompt, boolean allowed);
+        void onUserConsentResult(long nativeArCoreConsentPrompt, boolean allowed);
     }
 }
diff --git a/chrome/android/java/monochrome_public_bundle.proguard_flags.expected b/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
index 730cf54..8d4e368 100644
--- a/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
+++ b/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
@@ -117,6 +117,14 @@
   public static *** CREATOR;
 }
 
+# Keep all Fragment constructors since they are only usable via reflection.
+-keepclassmembers class * extends android.support.v4.app.Fragment {
+  public <init>();
+}
+-keepclassmembers class * extends androidx.fragment.app.Fragment {
+  public <init>();
+}
+
 # Don't obfuscate Parcelables as they might be marshalled outside Chrome.
 # If we annotated all Parcelables that get put into Bundles other than
 # for saveInstanceState (e.g. PendingIntents), then we could actually keep the
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index e3e5050..e4cc550 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -625,8 +625,8 @@
 
     <!-- History Navigation UI Item -->
     <dimen name="navigation_bubble_border_width">1dp</dimen>
-    <dimen name="navigation_bubble_default_height">48dp</dimen>
-    <dimen name="navigation_bubble_bg_vertical_inset">8dp</dimen>
+    <dimen name="navigation_bubble_default_height">32dp</dimen>
+    <dimen name="navigation_bubble_bg_vertical_inset">0dp</dimen>
     <dimen name="navigation_bubble_vertical_padding">4dp</dimen>
     <dimen name="navigation_bubble_horizontal_padding">8dp</dimen>
     <dimen name="navigation_bubble_icon_size">20dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridge.java
index fc92a54..b137528 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridge.java
@@ -6,15 +6,28 @@
 
 import android.annotation.TargetApi;
 import android.app.DownloadManager;
+import android.content.ContentResolver;
+import android.content.ContentValues;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Build;
+import android.os.Environment;
+import android.provider.MediaStore.MediaColumns;
+import android.text.format.DateUtils;
 
+import org.chromium.base.ContentUriUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
 /**
  * Since the {@link AndroidDownloadManager} can only be accessed from Java, this bridge will
  * transfer all C++ calls over to Java land for making the call to ADM.  This is a one-way bridge,
@@ -34,7 +47,8 @@
 
     /** Returns true if DownloadManager is installed on the phone. */
     @CalledByNative
-    private static boolean isAndroidDownloadManagerInstalled() {
+    @VisibleForTesting
+    public static boolean isAndroidDownloadManagerInstalled() {
         DownloadManager downloadManager = getDownloadManager();
         return (downloadManager != null);
     }
@@ -50,7 +64,8 @@
      * @return the download ID of this item as assigned by the download manager.
      */
     @CalledByNative
-    private static long addCompletedDownload(String title, String description, String path,
+    @VisibleForTesting
+    public static long addCompletedDownload(String title, String description, String path,
             long length, String uri, String referer) {
         try {
             // Call the proper version of the pass through based on the supported API level.
@@ -93,7 +108,8 @@
      * @return the number of IDs that were removed.
      */
     @CalledByNative
-    private static int remove(long[] ids) {
+    @VisibleForTesting
+    public static int remove(long[] ids) {
         DownloadManager downloadManager = getDownloadManager();
         try {
             if (downloadManager == null) return 0;
@@ -109,4 +125,84 @@
         return (DownloadManager) ContextUtils.getApplicationContext().getSystemService(
                 Context.DOWNLOAD_SERVICE);
     }
+
+    /**
+     * Adds an archive to the downloads collection on Android Q+. Preferred alternative to
+     * addCompletedDownload for Android Q and later.
+     *
+     * TODO(iwells): Remove reflection once API level 29 is supported.
+     *
+     * @param page Offline page to be published.
+     * @return Content URI referring to the published page.
+     */
+    @CalledByNative
+    @VisibleForTesting
+    public static String publishArchiveToDownloadsCollection(OfflinePageItem page) {
+        assert !org.chromium.base.BuildInfo.isAtLeastQ();
+
+        final String isPending = "is_pending"; // MediaStore.IS_PENDING
+
+        // Collect all fields for creating intermediate URI.
+        final long now = System.currentTimeMillis() / 1000;
+        ContentValues pendingValues = new ContentValues();
+        pendingValues.put(MediaColumns.DATE_ADDED, now);
+        pendingValues.put(MediaColumns.DATE_MODIFIED, now);
+        pendingValues.put(isPending, 1);
+        pendingValues.put("download_uri", page.getUrl()); // MediaStore.DownloadColumns.DOWNLOAD_URI
+
+        Uri externalDownloadUri;
+        try {
+            // Class android.provider.MediaStore.Downloads added in API level 29.
+            Class<?> downloadsClazz = Class.forName("android.provider.MediaStore$Downloads");
+            Field externalUriField = downloadsClazz.getDeclaredField("EXTERNAL_CONTENT_URI");
+            externalDownloadUri = (Uri) externalUriField.get(null);
+            Field primaryDirectoryField = MediaColumns.class.getDeclaredField("PRIMARY_DIRECTORY");
+            pendingValues.put(
+                    (String) primaryDirectoryField.get(null), Environment.DIRECTORY_DOWNLOADS);
+        } catch (Exception e) {
+            Log.d(TAG, "Unable to set pending download fields.", e);
+            return "";
+        }
+
+        // Pending URI will expire after 3 days.
+        long newExpirationTime = (System.currentTimeMillis() + 3 * DateUtils.DAY_IN_MILLIS) / 1000;
+        pendingValues.put("date_expires", newExpirationTime);
+
+        // Create intermediate URI.
+        ContentResolver contentResolver = ContextUtils.getApplicationContext().getContentResolver();
+        Uri intermediateUri = contentResolver.insert(externalDownloadUri, pendingValues);
+        if (intermediateUri == null || !ContentUriUtils.isContentUri(intermediateUri.toString())) {
+            Log.d(TAG, "Failed to create intermediate URI.");
+            return "";
+        }
+
+        // Copy archive to intermediate URI.
+        try {
+            // Class android.os.FileUtils added in API level 29.
+            Class<?> fileUtilsClazz = Class.forName("android.os.FileUtils");
+            Method copyMethod =
+                    fileUtilsClazz.getMethod("copy", InputStream.class, OutputStream.class);
+
+            OutputStream out = contentResolver.openOutputStream(intermediateUri);
+            InputStream in = new FileInputStream(page.getFilePath());
+            copyMethod.invoke(null, in, out);
+            in.close();
+            out.close();
+        } catch (Exception e) {
+            Log.d(TAG, "Unable to copy archive to pending URI.", e);
+            return "";
+        }
+
+        // Set display name, MIME type, and pending -> false.
+        final ContentValues publishValues = new ContentValues();
+        publishValues.put(isPending, 0);
+        publishValues.putNull("date_expires");
+        publishValues.put(MediaColumns.DISPLAY_NAME, page.getTitle());
+        publishValues.put(MediaColumns.MIME_TYPE, "multipart/related");
+        if (contentResolver.update(intermediateUri, publishValues, null, null) != 1) {
+            Log.d(TAG, "Failed to finish publishing archive.");
+        }
+
+        return intermediateUri.toString();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditorPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditorPreference.java
deleted file mode 100644
index bb3d562..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditorPreference.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2017 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.
-
-package org.chromium.chrome.browser.preferences.password;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.preference.Preference;
-
-import org.chromium.base.Callback;
-import org.chromium.chrome.browser.widget.prefeditor.EditorDialog;
-import org.chromium.chrome.browser.widget.prefeditor.PasswordEditor;
-
-/**
- * Launches the UI to create a credential.
- */
-public class PasswordEntryEditorPreference extends Preference {
-    final private Activity mActivity;
-    private EditorDialog mEditorDialog;
-    private Bundle mExtras;
-
-    public PasswordEntryEditorPreference(Activity activity) {
-        super(activity);
-        mActivity = activity;
-    }
-
-    /** @return The common editor user interface. */
-    public EditorDialog getEditorDialog() {
-        return mEditorDialog;
-    }
-
-    @Override
-    protected void onClick() {
-        mExtras = getExtras();
-        preparePasswordEditor();
-    }
-
-    private void preparePasswordEditor() {
-        mEditorDialog = new EditorDialog(mActivity, null /* observer */, null /* runnable */);
-        PasswordEditor passwordEditor = new PasswordEditor();
-        passwordEditor.setEditorDialog(mEditorDialog);
-
-        passwordEditor.edit(null /* toEdit */, new Callback<SavedPasswordEntry>() {
-            @Override
-            public void onResult(SavedPasswordEntry credential) {
-                PasswordManagerHandlerProvider.getInstance()
-                        .getPasswordManagerHandler()
-                        .updatePasswordLists();
-            }
-        });
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java
index 7394834..ef51870 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java
@@ -57,6 +57,11 @@
         return sArCoreInstance;
     }
 
+    @CalledByNative
+    private static ArCoreInstallUtils create(long nativeArCoreInstallUtils) {
+        return new ArCoreInstallUtils(nativeArCoreInstallUtils);
+    }
+
     private ArCoreInstallUtils(long nativeArCoreInstallUtils) {
         mNativeArCoreInstallUtils = nativeArCoreInstallUtils;
         // Need to be called before trying to access the AR module.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
index fac78e0..8b8dc7c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
@@ -4,81 +4,31 @@
 
 package org.chromium.chrome.browser.vr;
 
-import android.app.Activity;
 import android.content.Context;
 import android.view.Surface;
 
 import dalvik.system.BaseDexClassLoader;
 
-import org.chromium.base.BundleUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.infobar.InfoBarIdentifier;
-import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder;
-import org.chromium.chrome.browser.modules.ModuleInstallUi;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.components.module_installer.ModuleInstaller;
 
 /**
  * Provides ARCore classes access to java-related app functionality.
  */
 @JNINamespace("vr")
-public class ArCoreJavaUtils implements ModuleInstallUi.FailureUiListener {
+public class ArCoreJavaUtils {
     private static final String TAG = "ArCoreJavaUtils";
     private static final boolean DEBUG_LOGS = false;
 
     private long mNativeArCoreJavaUtils;
-    private boolean mAppInfoInitialized;
-    private Tab mTab;
 
     private ArImmersiveOverlay mArImmersiveOverlay;
 
-    // Instance that requested installation of ARCore.
-    // Should be non-null only if there is a pending request to install ARCore.
-    private static ArCoreJavaUtils sRequestInstallInstance;
-
-    // Cached ArCoreShim instance - valid only after AR module was installed and
-    // getArCoreShimInstance() was called.
-    private static ArCoreShim sArCoreInstance;
-
-    private static ArCoreShim getArCoreShimInstance() {
-        if (sArCoreInstance != null) return sArCoreInstance;
-
-        try {
-            sArCoreInstance =
-                    (ArCoreShim) Class.forName("org.chromium.chrome.browser.vr.ArCoreShimImpl")
-                            .newInstance();
-        } catch (ClassNotFoundException e) {
-            // shouldn't happen - we should only call this method once AR module is installed.
-            throw new RuntimeException(e);
-        } catch (InstantiationException e) {
-            throw new RuntimeException(e);
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException(e);
-        }
-
-        return sArCoreInstance;
-    }
-
-    public static void installArCoreDeviceProviderFactory() {
-        nativeInstallArCoreDeviceProviderFactory();
-    }
-
-    /**
-     * Gets the current application context.
-     *
-     * @return Context The application context.
-     */
-    @CalledByNative
-    private static Context getApplicationContext() {
-        return ContextUtils.getApplicationContext();
-    }
-
     @CalledByNative
     private static ArCoreJavaUtils create(long nativeArCoreJavaUtils) {
         ThreadUtils.assertOnUiThread();
@@ -93,22 +43,19 @@
         }
     }
 
-    @Override
-    public void onRetry() {
-        if (mNativeArCoreJavaUtils == 0) return;
-        requestInstallArModule(mTab);
-    }
-
-    @Override
-    public void onCancel() {
-        if (mNativeArCoreJavaUtils == 0) return;
-        nativeOnRequestInstallArModuleResult(mNativeArCoreJavaUtils, /* success = */ false);
+    /**
+     * Gets the current application context.
+     *
+     * @return Context The application context.
+     */
+    @CalledByNative
+    private static Context getApplicationContext() {
+        return ContextUtils.getApplicationContext();
     }
 
     private ArCoreJavaUtils(long nativeArCoreJavaUtils) {
         if (DEBUG_LOGS) Log.i(TAG, "constructor, nativeArCoreJavaUtils=" + nativeArCoreJavaUtils);
         mNativeArCoreJavaUtils = nativeArCoreJavaUtils;
-        initializeAppInfo();
     }
 
     @CalledByNative
@@ -151,194 +98,6 @@
         mNativeArCoreJavaUtils = 0;
     }
 
-    private void initializeAppInfo() {
-        mAppInfoInitialized = true;
-
-        // Need to be called before trying to access the AR module.
-        ModuleInstaller.getInstance().init();
-    }
-
-    private @ArCoreShim.Availability int getArCoreInstallStatus() {
-        return getArCoreShimInstance().checkAvailability(getApplicationContext());
-    }
-
-    @CalledByNative
-    private boolean shouldRequestInstallSupportedArCore() {
-        @ArCoreShim.Availability
-        int availability = getArCoreInstallStatus();
-        // Skip ARCore installation if we are certain that it is already installed.
-        // In all other cases, we might as well try to install it and handle installation failures.
-        return availability != ArCoreShim.Availability.SUPPORTED_INSTALLED;
-    }
-
-    @CalledByNative
-    private void requestInstallArModule(Tab tab) {
-        mTab = tab;
-        ModuleInstallUi ui = new ModuleInstallUi(mTab, R.string.ar_module_title, this);
-        ui.showInstallStartUi();
-        ModuleInstaller.getInstance().install("ar", success -> {
-            assert shouldRequestInstallArModule() != success;
-
-            if (success) {
-                // As per documentation, it's recommended to issue a call to
-                // ArCoreApk.checkAvailability() early in application lifecycle & ignore the result
-                // so that subsequent calls can return cached result:
-                // https://developers.google.com/ar/develop/java/enable-arcore
-                // This is as early in the app lifecycle as it gets for us - just after installing
-                // AR module.
-                getArCoreInstallStatus();
-            }
-
-            if (mNativeArCoreJavaUtils != 0) {
-                if (success) {
-                    ui.showInstallSuccessUi();
-                    nativeOnRequestInstallArModuleResult(mNativeArCoreJavaUtils, success);
-                } else {
-                    ui.showInstallFailureUi();
-                    // early exit - user will be offered a choice to retry & install flow will
-                    // continue from onRetry / onCancel
-                    return;
-                }
-            }
-        });
-    }
-
-    @CalledByNative
-    private void requestInstallSupportedArCore(final Tab tab) {
-        assert shouldRequestInstallSupportedArCore();
-
-        @ArCoreShim.Availability
-        int arCoreAvailability = getArCoreInstallStatus();
-        final Activity activity = tab.getActivity();
-        String infobarText = null;
-        String buttonText = null;
-        switch (arCoreAvailability) {
-            case ArCoreShim.Availability.UNSUPPORTED_DEVICE_NOT_CAPABLE:
-                maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false);
-                break;
-            case ArCoreShim.Availability.UNKNOWN_CHECKING:
-            case ArCoreShim.Availability.UNKNOWN_ERROR:
-            case ArCoreShim.Availability.UNKNOWN_TIMED_OUT:
-            case ArCoreShim.Availability.SUPPORTED_NOT_INSTALLED:
-                infobarText = activity.getString(R.string.ar_core_check_infobar_install_text);
-                buttonText = activity.getString(R.string.app_banner_install);
-                break;
-            case ArCoreShim.Availability.SUPPORTED_APK_TOO_OLD:
-                infobarText = activity.getString(R.string.ar_core_check_infobar_update_text);
-                buttonText = activity.getString(R.string.update_from_market);
-                break;
-            case ArCoreShim.Availability.SUPPORTED_INSTALLED:
-                assert false;
-                break;
-        }
-
-        SimpleConfirmInfoBarBuilder.Listener listener = new SimpleConfirmInfoBarBuilder.Listener() {
-            @Override
-            public void onInfoBarDismissed() {
-                maybeNotifyNativeOnRequestInstallSupportedArCoreResult(
-                        !shouldRequestInstallSupportedArCore());
-            }
-
-            @Override
-            public boolean onInfoBarButtonClicked(boolean isPrimary) {
-                try {
-                    assert sRequestInstallInstance == null;
-                    @ArCoreShim.InstallStatus
-                    int installStatus = getArCoreShimInstance().requestInstall(activity, true);
-
-                    if (installStatus == ArCoreShim.InstallStatus.INSTALL_REQUESTED) {
-                        // Install flow will resume in onArCoreRequestInstallReturned, mark that
-                        // there is active request. Native code notification will be deferred until
-                        // our activity gets resumed.
-                        sRequestInstallInstance = ArCoreJavaUtils.this;
-                    } else if (installStatus == ArCoreShim.InstallStatus.INSTALLED) {
-                        // No need to install - notify native code.
-                        maybeNotifyNativeOnRequestInstallSupportedArCoreResult(true);
-                    }
-
-                } catch (ArCoreShim.UnavailableDeviceNotCompatibleException e) {
-                    sRequestInstallInstance = null;
-                    Log.w(TAG, "ARCore installation request failed with exception: %s",
-                            e.toString());
-
-                    maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false);
-                } catch (ArCoreShim.UnavailableUserDeclinedInstallationException e) {
-                    maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false);
-                }
-
-                return false;
-            }
-
-            @Override
-            public boolean onInfoBarLinkClicked() {
-                return false;
-            }
-        };
-        // TODO(ijamardo, https://crbug.com/838833): Add icon for AR info bar.
-        SimpleConfirmInfoBarBuilder.create(tab, listener, InfoBarIdentifier.AR_CORE_UPGRADE_ANDROID,
-                R.drawable.ic_error_outline_googblue_24dp, infobarText, buttonText, null, null,
-                true);
-    }
-
-    @CalledByNative
-    private boolean canRequestInstallArModule() {
-        // We can only try to install the AR module if we are in a bundle mode.
-        return BundleUtils.isBundle();
-    }
-
-    @CalledByNative
-    private boolean shouldRequestInstallArModule() {
-        try {
-            // Try to find class in AR module that has not been obfuscated.
-            Class.forName("com.google.ar.core.ArCoreApk");
-            return false;
-        } catch (ClassNotFoundException e) {
-            return true;
-        }
-    }
-
-    private void onArCoreRequestInstallReturned(Activity activity) {
-        try {
-            // Since |userRequestedInstall| parameter is false, the below call should
-            // throw if ARCore is still not installed - no need to check the result.
-            getArCoreShimInstance().requestInstall(activity, false);
-            maybeNotifyNativeOnRequestInstallSupportedArCoreResult(true);
-        } catch (ArCoreShim.UnavailableDeviceNotCompatibleException e) {
-            Log.w(TAG, "Exception thrown when trying to validate install state of ARCore: %s",
-                    e.toString());
-            maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false);
-        } catch (ArCoreShim.UnavailableUserDeclinedInstallationException e) {
-            maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false);
-        }
-    }
-
-    /**
-     * This method should be called by the Activity that gets resumed.
-     * We are only interested in the cases where our current Activity got paused
-     * as a result of a call to ArCoreApk.requestInstall() method.
-     */
-    public static void onResumeActivityWithNative(Activity activity) {
-        if (sRequestInstallInstance != null) {
-            sRequestInstallInstance.onArCoreRequestInstallReturned(activity);
-            sRequestInstallInstance = null;
-        }
-    }
-
-    /**
-     * Helper used to notify native code about the result of the request to install ARCore.
-     */
-    private void maybeNotifyNativeOnRequestInstallSupportedArCoreResult(boolean success) {
-        if (mNativeArCoreJavaUtils != 0) {
-            nativeOnRequestInstallSupportedArCoreResult(mNativeArCoreJavaUtils, success);
-        }
-    }
-
-    private static native void nativeInstallArCoreDeviceProviderFactory();
-    private native void nativeOnRequestInstallArModuleResult(
-            long nativeArCoreJavaUtils, boolean success);
-    private native void nativeOnRequestInstallSupportedArCoreResult(
-            long nativeArCoreJavaUtils, boolean success);
-
     private native void nativeOnDrawingSurfaceReady(
             long nativeArCoreJavaUtils, Surface surface, int rotation, int width, int height);
     private native void nativeOnDrawingSurfaceTouch(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java
index 9fc202e..500cb1c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java
@@ -19,11 +19,11 @@
 
     @Override
     public void init() {
-        ArCoreJavaUtils.installArCoreDeviceProviderFactory();
+        ArCoreInstallUtils.installArCoreDeviceProviderFactory();
     }
 
     @Override
     public void registerOnResumeActivity(Activity activity) {
-        ArCoreJavaUtils.onResumeActivityWithNative(activity);
+        ArCoreInstallUtils.onResumeActivityWithNative(activity);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 54c5a5c..562d8ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -25,6 +25,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ObserverList;
+import org.chromium.base.Supplier;
 import org.chromium.base.SysUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
@@ -36,8 +37,6 @@
 import org.chromium.chrome.browser.native_page.NativePageHost;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabBrowserControlsState;
-import org.chromium.chrome.browser.tabmodel.TabLaunchType;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.toolbar.top.ActionModeController.ActionBarDelegate;
 import org.chromium.chrome.browser.toolbar.top.ViewShiftingActionBarDelegate;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
@@ -131,15 +130,6 @@
     /** The height ratio for the sheet in the SheetState.HALF state. */
     private static final float HALF_HEIGHT_RATIO = 0.75f;
 
-    /** The fraction of the width of the screen that, when swiped, will cause the sheet to move. */
-    private static final float SWIPE_ALLOWED_FRACTION = 0.2f;
-
-    /**
-     * The minimum swipe velocity (dp/ms) that should be considered as a user opening the bottom
-     * sheet intentionally. This is specifically for the 'velocity' swipe logic.
-     */
-    private static final float SHEET_SWIPE_MIN_DP_PER_MS = 0.2f;
-
     /** The desired height of a content that has just been shown or whose height was invalidated. */
     private static final float HEIGHT_UNSPECIFIED = -1.0f;
 
@@ -201,7 +191,7 @@
     private int mTargetState = SheetState.NONE;
 
     /** Used for getting the current tab. */
-    protected TabModelSelector mTabModelSelector;
+    protected Supplier<Tab> mTabSupplier;
 
     /** The fullscreen manager for information about toolbar offsets. */
     private ChromeFullscreenManager mFullscreenManager;
@@ -559,7 +549,7 @@
      * @param activity The activity displaying the bottom sheet.
      */
     public void init(View root, ChromeActivity activity) {
-        mTabModelSelector = activity.getTabModelSelector();
+        mTabSupplier = activity.getActivityTabProvider();
         mFullscreenManager = activity.getFullscreenManager();
 
         int colorId = R.color.sheet_bg_color;
@@ -723,17 +713,9 @@
     public int loadUrl(LoadUrlParams params, boolean incognito) {
         for (BottomSheetObserver o : mObservers) o.onLoadUrl(params.getUrl());
 
-        assert mTabModelSelector != null;
-
         int tabLoadStatus = TabLoadStatus.DEFAULT_PAGE_LOAD;
 
-        if (getActiveTab() != null && getActiveTab().isIncognito() == incognito) {
-            tabLoadStatus = getActiveTab().loadUrl(params);
-        } else {
-            // If no compatible tab is active behind the sheet, open a new one.
-            mTabModelSelector.openNewTab(
-                    params, TabLaunchType.FROM_CHROME_UI, getActiveTab(), incognito);
-        }
+        if (getActiveTab() != null) tabLoadStatus = getActiveTab().loadUrl(params);
 
         return tabLoadStatus;
     }
@@ -751,7 +733,7 @@
 
     @Override
     public Tab getActiveTab() {
-        return mTabModelSelector != null ? mTabModelSelector.getCurrentTab() : null;
+        return mTabSupplier != null ? mTabSupplier.get() : null;
     }
 
     @Override
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index d65826c..ba37432 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -47,6 +47,7 @@
 
 if (enable_arcore) {
   chrome_java_sources += [
+    "java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java",
     "java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java",
     "java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java",
     "java/src/org/chromium/chrome/browser/vr/ArCoreShim.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridgeTest.java
new file mode 100644
index 0000000..889bba9
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridgeTest.java
@@ -0,0 +1,171 @@
+// Copyright 2019 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.
+
+package org.chromium.chrome.browser.offlinepages;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ContentUriUtils;
+import org.chromium.base.task.PostTask;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisableIf;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.OfflinePageModelObserver;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.SavePageCallback;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.net.NetworkChangeNotifier;
+import org.chromium.net.test.EmbeddedTestServer;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/** Unit tests for {@link OfflinePageArchivePublisherBridge}. */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class OfflinePageArchivePublisherBridgeTest {
+    @Rule
+    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
+
+    private static final String TEST_PAGE = "/chrome/test/data/android/about.html";
+    private static final int TIMEOUT_MS = 5000;
+    private static final ClientId TEST_CLIENT_ID =
+            new ClientId(OfflinePageBridge.DOWNLOAD_NAMESPACE, "1234");
+
+    private OfflinePageBridge mOfflinePageBridge;
+    private EmbeddedTestServer mTestServer;
+    private String mTestPage;
+
+    private void initializeBridgeForProfile(final boolean incognitoProfile)
+            throws InterruptedException {
+        final Semaphore semaphore = new Semaphore(0);
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+            Profile profile = Profile.getLastUsedProfile();
+            if (incognitoProfile) {
+                profile = profile.getOffTheRecordProfile();
+            }
+            // Ensure we start in an offline state.
+            mOfflinePageBridge = OfflinePageBridge.getForProfile(profile);
+            if (mOfflinePageBridge == null || mOfflinePageBridge.isOfflinePageModelLoaded()) {
+                semaphore.release();
+                return;
+            }
+            mOfflinePageBridge.addObserver(new OfflinePageModelObserver() {
+                @Override
+                public void offlinePageModelLoaded() {
+                    semaphore.release();
+                    mOfflinePageBridge.removeObserver(this);
+                }
+            });
+        });
+        Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        if (!incognitoProfile) Assert.assertNotNull(mOfflinePageBridge);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            // Ensure we start in an offline state.
+            NetworkChangeNotifier.forceConnectivityState(false);
+            if (!NetworkChangeNotifier.isInitialized()) {
+                NetworkChangeNotifier.init();
+            }
+        });
+
+        initializeBridgeForProfile(false);
+
+        mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+        mTestPage = mTestServer.getURL(TEST_PAGE);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mTestServer.stopAndDestroyServer();
+    }
+
+    // TODO(iwells): Change "29" to "Build.VERSION_CODES.Q" when it's available.
+    @Test
+    @SmallTest
+    @DisableIf.Build(sdk_is_greater_than = 28)
+    public void testAddCompletedDownload() throws InterruptedException, TimeoutException {
+        Assert.assertTrue(OfflinePageArchivePublisherBridge.isAndroidDownloadManagerInstalled());
+
+        mActivityTestRule.loadUrl(mTestPage);
+        savePage(TEST_CLIENT_ID);
+        OfflinePageItem page = OfflineTestUtil.getAllPages().get(0);
+
+        long downloadId = OfflinePageArchivePublisherBridge.addCompletedDownload(page.getTitle(),
+                "description", page.getFilePath(), page.getFileSize(), page.getUrl(), "");
+
+        Assert.assertNotEquals(0L, downloadId);
+    }
+
+    @Test
+    @SmallTest
+    @DisableIf.Build(sdk_is_greater_than = 28)
+    public void testRemove() throws InterruptedException, TimeoutException {
+        Assert.assertTrue(OfflinePageArchivePublisherBridge.isAndroidDownloadManagerInstalled());
+
+        mActivityTestRule.loadUrl(mTestPage);
+        savePage(TEST_CLIENT_ID);
+        OfflinePageItem page = OfflineTestUtil.getAllPages().get(0);
+
+        long downloadId = OfflinePageArchivePublisherBridge.addCompletedDownload(page.getTitle(),
+                "description", page.getFilePath(), page.getFileSize(), page.getUrl(), "");
+
+        Assert.assertNotEquals(0L, downloadId);
+
+        long[] ids = new long[] {downloadId};
+        Assert.assertEquals(1, OfflinePageArchivePublisherBridge.remove(ids));
+    }
+
+    @Test
+    @SmallTest
+    @MinAndroidSdkLevel(29)
+    public void testPublishArchiveToDownloadsCollection()
+            throws InterruptedException, TimeoutException {
+        // Save a page and publish.
+        mActivityTestRule.loadUrl(mTestPage);
+        savePage(TEST_CLIENT_ID);
+        OfflinePageItem page = OfflineTestUtil.getAllPages().get(0);
+
+        String publishedUri =
+                OfflinePageArchivePublisherBridge.publishArchiveToDownloadsCollection(page);
+        Assert.assertFalse(publishedUri.isEmpty());
+        Assert.assertTrue(ContentUriUtils.isContentUri(publishedUri));
+        Assert.assertTrue(ContentUriUtils.contentUriExists(publishedUri));
+    }
+
+    // Returns offline ID.
+    private void savePage(final ClientId clientId) throws InterruptedException {
+        final Semaphore semaphore = new Semaphore(0);
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mOfflinePageBridge.savePage(
+                    mActivityTestRule.getWebContents(), clientId, new SavePageCallback() {
+                        @Override
+                        public void onSavePageDone(int savePageResult, String url, long offlineId) {
+                            semaphore.release();
+                        }
+                    });
+        });
+        Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java
index 77c0d4b..06e8086 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java
@@ -69,7 +69,7 @@
         Tab tab = mActivityTestRule.getActivity().getActivityTab();
 
         // Load and save an offline page.
-        savePage(testUrl);
+        savePage(testUrl, CLIENT_ID);
         Assert.assertFalse(isErrorPage(tab));
         Assert.assertFalse(isOfflinePage(tab));
 
@@ -101,7 +101,7 @@
         Tab tab = mActivityTestRule.getActivity().getActivityTab();
 
         // Load and save an offline page for the url with a fragment.
-        savePage(testUrlWithFragment);
+        savePage(testUrlWithFragment, CLIENT_ID);
         Assert.assertFalse(isErrorPage(tab));
         Assert.assertFalse(isOfflinePage(tab));
 
@@ -116,13 +116,47 @@
         Assert.assertTrue(isOfflinePage(tab));
     }
 
-    private void savePage(String url) throws InterruptedException {
+    @Test
+    @SmallTest
+    @DisabledTest(message = "crbug.com/786233")
+    public void testLoadOfflinePageFromDownloadsOnDisconnectedNetwork() throws Exception {
+        // Specifically tests saving to and loading from Downloads.
+        EmbeddedTestServer testServer =
+                EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+        String testUrl = testServer.getURL(TEST_PAGE);
+        String aboutUrl = testServer.getURL(ABOUT_PAGE);
+
+        Tab tab = mActivityTestRule.getActivity().getActivityTab();
+
+        // Load and save a persistent offline page using a persistent namespace so that the archive
+        // will be published.
+        savePage(testUrl, new ClientId(OfflinePageBridge.DOWNLOAD_NAMESPACE, "1234"));
+        Assert.assertFalse(isErrorPage(tab));
+        Assert.assertFalse(isOfflinePage(tab));
+
+        // Load another page.
+        mActivityTestRule.loadUrl(aboutUrl);
+        Assert.assertFalse(isErrorPage(tab));
+        Assert.assertFalse(isOfflinePage(tab));
+
+        // Stop the server and also disconnect the network.
+        testServer.stopAndDestroyServer();
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { NetworkChangeNotifier.forceConnectivityState(false); });
+
+        // Load the page that has an offline copy. The offline page should be shown.
+        mActivityTestRule.loadUrl(testUrl);
+        Assert.assertFalse(isErrorPage(tab));
+        Assert.assertTrue(isOfflinePage(tab));
+    }
+
+    private void savePage(String url, ClientId clientId) throws InterruptedException {
         mActivityTestRule.loadUrl(url);
 
         final Semaphore semaphore = new Semaphore(0);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mOfflinePageBridge.savePage(
-                    mActivityTestRule.getWebContents(), CLIENT_ID, new SavePageCallback() {
+                    mActivityTestRule.getWebContents(), clientId, new SavePageCallback() {
                         @Override
                         public void onSavePageDone(int savePageResult, String url, long offlineId) {
                             Assert.assertEquals(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserCompositorViewHolderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserCompositorViewHolderTest.java
index 39ced52..bd668be 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserCompositorViewHolderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserCompositorViewHolderTest.java
@@ -6,6 +6,7 @@
 
 import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_SVR;
 
+import android.os.Build;
 import android.support.test.filters.MediumTest;
 import android.view.ViewGroup;
 
@@ -15,6 +16,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
@@ -48,6 +50,8 @@
      */
     @Test
     @MediumTest
+    @DisableIf.
+    Build(sdk_is_less_than = Build.VERSION_CODES.LOLLIPOP, message = "https://crbug.com/984943")
     public void testResizeWithCompositorViewHolderDetached()
             throws InterruptedException, TimeoutException {
         final AtomicInteger oldWidth = new AtomicInteger();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
index 7f23715..1d33967 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
@@ -16,6 +16,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.PointF;
+import android.os.Build;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
@@ -29,6 +30,7 @@
 
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
@@ -127,6 +129,8 @@
     @Test
     @Restriction(RESTRICTION_TYPE_DEVICE_NON_DAYDREAM)
     @MediumTest
+    @DisableIf.
+    Build(sdk_is_less_than = Build.VERSION_CODES.LOLLIPOP, message = "https://crbug.com/984943")
     public void test2dtoVrShellNfcUnsupported() {
         enterVrShellNfc(false /* supported */);
     }
@@ -194,6 +198,8 @@
     @Test
     @Restriction(RESTRICTION_TYPE_DEVICE_NON_DAYDREAM)
     @MediumTest
+    @DisableIf.
+    Build(sdk_is_less_than = Build.VERSION_CODES.LOLLIPOP, message = "https://crbug.com/984943")
     public void test2dtoVrShellto2dUnsupported() {
         enterExitVrShell(false /* supported */);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrDeviceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrDeviceTest.java
index c9e9867..f0ffce8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrDeviceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrDeviceTest.java
@@ -25,6 +25,7 @@
 import org.chromium.base.test.params.ParameterSet;
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeSwitches;
@@ -95,6 +96,8 @@
     @MediumTest
     @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
     @Restriction(RESTRICTION_TYPE_SVR)
+    @DisableIf.
+    Build(sdk_is_less_than = Build.VERSION_CODES.LOLLIPOP, message = "https://crbug.com/984943")
     // Sensorless still works on older devices since it doesn't rely on anything in the DFM.
     public void testGvrlessMagicWindowCapabilities() throws InterruptedException {
         // Make Chrome think that VrCore is not installed
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 6826d3f..0c7cbe9 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4985,9 +4985,6 @@
       <message name="IDS_NTP_CONFIRM_MSG_RESTORE_DEFAULTS" desc="The text label of the restore default shortcuts button when editing a custom link. (On the New Tab Page)">
         Restore default shortcuts
       </message>
-      <message name="IDS_NTP_CUSTOM_BG_CUSTOMIZE_BACKGROUND" desc="The title and aria-label for the tooltip for background customization. (On the New Tab Page)">
-        Customize this page
-      </message>
       <message name="IDS_NTP_CUSTOM_BG_CHROME_WALLPAPERS" desc="The text label of the Chrome backgrounds option for background customization.(On the New Tab Page)">
         Chrome backgrounds
       </message>
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_CUSTOM_BG_CUSTOMIZE_BACKGROUND.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_CUSTOM_BG_CUSTOMIZE_BACKGROUND.png.sha1
deleted file mode 100644
index 215f8ad..0000000
--- a/chrome/app/generated_resources_grd/IDS_NTP_CUSTOM_BG_CUSTOMIZE_BACKGROUND.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-32af17f468186a40fb77e59126316f966d369ef1
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 0e6093e6..f90d9881 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1533,6 +1533,8 @@
     "sharing/sharing_fcm_sender.cc",
     "sharing/sharing_fcm_sender.h",
     "sharing/sharing_message_handler.h",
+    "sharing/sharing_metrics.cc",
+    "sharing/sharing_metrics.h",
     "sharing/sharing_service.cc",
     "sharing/sharing_service.h",
     "sharing/sharing_service_factory.cc",
@@ -4931,6 +4933,10 @@
       "supervised_user/experimental/supervised_user_blacklist.h",
       "supervised_user/experimental/supervised_user_filtering_switches.cc",
       "supervised_user/experimental/supervised_user_filtering_switches.h",
+      "supervised_user/kids_chrome_management/kids_chrome_management_client.cc",
+      "supervised_user/kids_chrome_management/kids_chrome_management_client.h",
+      "supervised_user/kids_chrome_management/kids_chrome_management_client_factory.cc",
+      "supervised_user/kids_chrome_management/kids_chrome_management_client_factory.h",
       "supervised_user/kids_management_url_checker_client.cc",
       "supervised_user/kids_management_url_checker_client.h",
       "supervised_user/permission_request_creator.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index f16b24e..2473cb3f 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3361,11 +3361,6 @@
      flag_descriptions::kLookalikeUrlNavigationSuggestionsDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kLookalikeUrlNavigationSuggestionsUI)},
 
-    {"sync-USS-autofill-wallet-metadata",
-     flag_descriptions::kSyncUSSAutofillWalletMetadataName,
-     flag_descriptions::kSyncUSSAutofillWalletMetadataDescription, kOsAll,
-     FEATURE_VALUE_TYPE(switches::kSyncUSSAutofillWalletMetadata)},
-
     {"enable-resampling-input-events",
      flag_descriptions::kEnableResamplingInputEventsName,
      flag_descriptions::kEnableResamplingInputEventsDescription, kOsAll,
diff --git a/chrome/browser/android/profiles/profile_downloader_android.cc b/chrome/browser/android/profiles/profile_downloader_android.cc
index 45b4d2c..83cfcf7 100644
--- a/chrome/browser/android/profiles/profile_downloader_android.cc
+++ b/chrome/browser/android/profiles/profile_downloader_android.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
+#include "content/public/browser/storage_partition.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/android/java_bitmap.h"
@@ -62,8 +63,14 @@
     return desired_image_side_pixels_;
   }
 
-  Profile* GetBrowserProfile() override {
-    return profile_;
+  identity::IdentityManager* GetIdentityManager() override {
+    return IdentityManagerFactory::GetForProfile(profile_);
+  }
+
+  network::mojom::URLLoaderFactory* GetURLLoaderFactory() override {
+    return content::BrowserContext::GetDefaultStoragePartition(profile_)
+        ->GetURLLoaderFactoryForBrowserProcess()
+        .get();
   }
 
   std::string GetCachedPictureURL() const override {
diff --git a/chrome/browser/android/vr/BUILD.gn b/chrome/browser/android/vr/BUILD.gn
index e17977b..d6c5c83 100644
--- a/chrome/browser/android/vr/BUILD.gn
+++ b/chrome/browser/android/vr/BUILD.gn
@@ -83,9 +83,9 @@
       "arcore_device/arcore_gl_thread.h",
       "arcore_device/arcore_impl.cc",
       "arcore_device/arcore_impl.h",
-      "arcore_device/arcore_install_utils.h",
       "arcore_device/arcore_java_utils.cc",
       "arcore_device/arcore_java_utils.h",
+      "arcore_device/arcore_session_utils.h",
       "arcore_device/arcore_shim.cc",
       "arcore_device/arcore_shim.h",
       "arcore_device/type_converters.cc",
@@ -222,6 +222,7 @@
 if (enable_arcore) {
   generate_jni("ar_jni_headers") {
     sources = [
+      "//chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java",
       "//chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java",
     ]
   }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.cc b/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.cc
index b1fe89a5..1e75f79 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.cc
@@ -4,13 +4,17 @@
 
 #include "chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
 #include "chrome/android/features/vr/jni_headers/ArConsentDialog_jni.h"
 #include "chrome/browser/android/tab_android.h"
+#include "chrome/browser/android/vr/ar_jni_headers/ArCoreInstallUtils_jni.h"
+#include "chrome/browser/android/vr/arcore_device/arcore_device_provider.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "device/vr/android/arcore/arcore_device_provider_factory.h"
 
 using base::android::AttachCurrentThread;
 using base::android::ScopedJavaLocalRef;
@@ -19,7 +23,21 @@
 
 namespace {
 
-ArcoreConsentPrompt* g_instance = nullptr;
+class ArCoreDeviceProviderFactoryImpl
+    : public device::ArCoreDeviceProviderFactory {
+ public:
+  ArCoreDeviceProviderFactoryImpl() = default;
+  ~ArCoreDeviceProviderFactoryImpl() override = default;
+  std::unique_ptr<device::VRDeviceProvider> CreateDeviceProvider() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ArCoreDeviceProviderFactoryImpl);
+};
+
+std::unique_ptr<device::VRDeviceProvider>
+ArCoreDeviceProviderFactoryImpl::CreateDeviceProvider() {
+  return std::make_unique<device::ArCoreDeviceProvider>();
+}
 
 base::android::ScopedJavaLocalRef<jobject> GetTabFromRenderer(
     int render_process_id,
@@ -44,42 +62,171 @@
 
 }  // namespace
 
-ArcoreConsentPrompt::ArcoreConsentPrompt() = default;
+ArCoreConsentPrompt::ArCoreConsentPrompt() : weak_ptr_factory_(this) {}
 
-ArcoreConsentPrompt::~ArcoreConsentPrompt() = default;
+ArCoreConsentPrompt::~ArCoreConsentPrompt() = default;
 
-void ArcoreConsentPrompt::GetUserPermission(
+void ArCoreConsentPrompt::OnUserConsentResult(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& j_caller,
+    jboolean is_granted) {
+  jdelegate_.Reset();
+
+  if (!on_user_consent_callback_)
+    return;
+
+  if (!is_granted) {
+    CallDeferredUserConsentCallback(false);
+    return;
+  }
+
+  java_install_utils_ =
+      Java_ArCoreInstallUtils_create(env, reinterpret_cast<jlong>(this));
+
+  if (java_install_utils_.is_null()) {
+    CallDeferredUserConsentCallback(false);
+    return;
+  }
+
+  RequestArModule();
+}
+
+// static
+void ArCoreConsentPrompt::ShowConsentPrompt(
     int render_process_id,
     int render_frame_id,
     base::OnceCallback<void(bool)> response_callback) {
   on_user_consent_callback_ = std::move(response_callback);
+  render_process_id_ = render_process_id;
+  render_frame_id_ = render_frame_id;
 
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> jdelegate = Java_ArConsentDialog_showDialog(
+  jdelegate_ = Java_ArConsentDialog_showDialog(
       env, reinterpret_cast<jlong>(this),
-      GetTabFromRenderer(render_process_id, render_frame_id));
-  if (jdelegate.is_null()) {
+      GetTabFromRenderer(render_process_id_, render_frame_id_));
+  if (jdelegate_.is_null()) {
     std::move(on_user_consent_callback_).Run(false);
   }
 }
 
-void ArcoreConsentPrompt::OnUserConsentResult(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& j_caller,
-    jboolean is_granted) {
-  DCHECK(on_user_consent_callback_);
-  std::move(on_user_consent_callback_).Run(is_granted);
+bool ArCoreConsentPrompt::CanRequestInstallArModule() {
+  return Java_ArCoreInstallUtils_canRequestInstallArModule(
+      AttachCurrentThread(), java_install_utils_);
 }
 
-// static
-void ArcoreConsentPrompt::ShowConsentPrompt(
-    int render_process_id,
-    int render_frame_id,
-    base::OnceCallback<void(bool)> response_callback) {
-  if (!g_instance)
-    g_instance = new ArcoreConsentPrompt();
-  g_instance->GetUserPermission(render_process_id, render_frame_id,
-                                std::move(response_callback));
+bool ArCoreConsentPrompt::ShouldRequestInstallArModule() {
+  return Java_ArCoreInstallUtils_shouldRequestInstallArModule(
+      AttachCurrentThread(), java_install_utils_);
+}
+
+void ArCoreConsentPrompt::RequestInstallArModule() {
+  Java_ArCoreInstallUtils_requestInstallArModule(
+      AttachCurrentThread(), java_install_utils_,
+      GetTabFromRenderer(render_process_id_, render_frame_id_));
+}
+
+bool ArCoreConsentPrompt::ShouldRequestInstallSupportedArCore() {
+  JNIEnv* env = AttachCurrentThread();
+  return Java_ArCoreInstallUtils_shouldRequestInstallSupportedArCore(
+      env, java_install_utils_);
+}
+
+void ArCoreConsentPrompt::RequestInstallSupportedArCore() {
+  DCHECK(ShouldRequestInstallSupportedArCore());
+
+  JNIEnv* env = AttachCurrentThread();
+  Java_ArCoreInstallUtils_requestInstallSupportedArCore(
+      env, java_install_utils_,
+      GetTabFromRenderer(render_process_id_, render_frame_id_));
+}
+
+void ArCoreConsentPrompt::OnRequestInstallArModuleResult(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    bool success) {
+  DVLOG(1) << __func__;
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  if (on_request_ar_module_result_callback_) {
+    std::move(on_request_ar_module_result_callback_).Run(success);
+  }
+}
+
+void ArCoreConsentPrompt::OnRequestInstallSupportedArCoreResult(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    bool success) {
+  DVLOG(1) << __func__;
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(on_request_arcore_install_or_update_result_callback_);
+
+  std::move(on_request_arcore_install_or_update_result_callback_).Run(success);
+}
+
+void ArCoreConsentPrompt::RequestArModule() {
+  DVLOG(1) << __func__;
+  if (ShouldRequestInstallArModule()) {
+    if (!CanRequestInstallArModule()) {
+      OnRequestArModuleResult(false);
+      return;
+    }
+
+    on_request_ar_module_result_callback_ = base::BindOnce(
+        &ArCoreConsentPrompt::OnRequestArModuleResult, GetWeakPtr());
+    RequestInstallArModule();
+    return;
+  }
+
+  OnRequestArModuleResult(true);
+}
+
+void ArCoreConsentPrompt::OnRequestArModuleResult(bool success) {
+  DVLOG(3) << __func__ << ": success=" << success;
+
+  if (!success) {
+    CallDeferredUserConsentCallback(false);
+    return;
+  }
+
+  RequestArCoreInstallOrUpdate();
+}
+
+void ArCoreConsentPrompt::RequestArCoreInstallOrUpdate() {
+  DVLOG(1) << __func__;
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(!on_request_arcore_install_or_update_result_callback_);
+
+  if (ShouldRequestInstallSupportedArCore()) {
+    // ARCore is not installed or requires an update. Store the callback to be
+    // processed later once installation/update is complete or got cancelled.
+    on_request_arcore_install_or_update_result_callback_ = base::BindOnce(
+        &ArCoreConsentPrompt::OnRequestArCoreInstallOrUpdateResult,
+        GetWeakPtr());
+
+    RequestInstallSupportedArCore();
+    return;
+  }
+
+  OnRequestArCoreInstallOrUpdateResult(true);
+}
+
+void ArCoreConsentPrompt::OnRequestArCoreInstallOrUpdateResult(bool success) {
+  DVLOG(1) << __func__;
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  CallDeferredUserConsentCallback(success);
+}
+
+void ArCoreConsentPrompt::CallDeferredUserConsentCallback(
+    bool is_permission_granted) {
+  if (on_user_consent_callback_)
+    std::move(on_user_consent_callback_).Run(is_permission_granted);
+}
+
+static void JNI_ArCoreInstallUtils_InstallArCoreDeviceProviderFactory(
+    JNIEnv* env) {
+  device::ArCoreDeviceProviderFactory::Install(
+      std::make_unique<ArCoreDeviceProviderFactoryImpl>());
 }
 
 }  // namespace vr
diff --git a/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h b/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h
index 257d5ab..45a27a5 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h
@@ -7,33 +7,74 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_weak_ref.h"
+#include "base/android/scoped_java_ref.h"
 #include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/vr/service/arcore_consent_prompt_interface.h"
 #include "chrome/browser/vr/vr_export.h"
 
 namespace vr {
 
-class VR_EXPORT ArcoreConsentPrompt : public ArcoreConsentPromptInterface {
+class VR_EXPORT ArCoreConsentPrompt : public ArCoreConsentPromptInterface {
  public:
+  ArCoreConsentPrompt();
+  ~ArCoreConsentPrompt();
+
+  // ArCoreConsentPromptInterface:
   void ShowConsentPrompt(
       int render_process_id,
       int render_frame_id,
       base::OnceCallback<void(bool)> response_callback) override;
 
-  ArcoreConsentPrompt();
-  ~ArcoreConsentPrompt();
-
-  // device::VrDevicePermissionProvider:
-  void GetUserPermission(int render_process_id,
-                         int render_frame_id,
-                         base::OnceCallback<void(bool)> response_callback);
-
+  // Called from Java end.
   void OnUserConsentResult(JNIEnv* env,
                            const base::android::JavaParamRef<jobject>& j_caller,
                            jboolean is_granted);
+  void OnRequestInstallArModuleResult(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      bool success);
+  void OnRequestInstallSupportedArCoreResult(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      bool success);
 
  private:
+  // Returns true if AR module installation is supported, false otherwise.
+  bool CanRequestInstallArModule();
+  // Returns true if AR module is not installed, false otherwise.
+  bool ShouldRequestInstallArModule();
+  void RequestInstallArModule();
+  bool ShouldRequestInstallSupportedArCore();
+  void RequestInstallSupportedArCore();
+
+  void RequestArModule();
+  void OnRequestArModuleResult(bool success);
+  void RequestArCoreInstallOrUpdate();
+  void OnRequestArCoreInstallOrUpdateResult(bool success);
+
+  void CallDeferredUserConsentCallback(bool is_permission_granted);
+
+  base::WeakPtr<ArCoreConsentPrompt> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
   base::OnceCallback<void(bool)> on_user_consent_callback_;
+
+  base::OnceCallback<void(bool)> on_request_ar_module_result_callback_;
+  base::OnceCallback<void(bool)>
+      on_request_arcore_install_or_update_result_callback_;
+
+  base::android::ScopedJavaGlobalRef<jobject> jdelegate_;
+  int render_process_id_;
+  int render_frame_id_;
+
+  base::android::ScopedJavaGlobalRef<jobject> java_install_utils_;
+  THREAD_CHECKER(thread_checker_);
+
+  base::WeakPtrFactory<ArCoreConsentPrompt> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(ArCoreConsentPrompt);
 };
 
 }  // namespace vr
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device.cc b/chrome/browser/android/vr/arcore_device/arcore_device.cc
index 535231c..205e130c 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_device.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_device.cc
@@ -14,8 +14,8 @@
 #include "chrome/browser/android/vr/arcore_device/arcore_gl.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_gl_thread.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_impl.h"
-#include "chrome/browser/android/vr/arcore_device/arcore_install_utils.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_java_utils.h"
+#include "chrome/browser/android/vr/arcore_device/arcore_session_utils.h"
 #include "chrome/browser/android/vr/mailbox_to_surface_bridge.h"
 #include "chrome/browser/permissions/permission_manager.h"
 #include "chrome/browser/permissions/permission_result.h"
@@ -74,13 +74,13 @@
     std::unique_ptr<ArCoreFactory> arcore_factory,
     std::unique_ptr<ArImageTransportFactory> ar_image_transport_factory,
     std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_to_surface_bridge,
-    std::unique_ptr<vr::ArCoreInstallUtils> arcore_install_utils)
+    std::unique_ptr<vr::ArCoreSessionUtils> arcore_session_utils)
     : VRDeviceBase(mojom::XRDeviceId::ARCORE_DEVICE_ID),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       arcore_factory_(std::move(arcore_factory)),
       ar_image_transport_factory_(std::move(ar_image_transport_factory)),
       mailbox_bridge_(std::move(mailbox_to_surface_bridge)),
-      arcore_install_utils_(std::move(arcore_install_utils)),
+      arcore_session_utils_(std::move(arcore_session_utils)),
       session_state_(std::make_unique<ArCoreDevice::SessionState>()),
       weak_ptr_factory_(this) {
   // Ensure display_info_ is set to avoid crash in CallDeferredSessionCallback
@@ -97,25 +97,16 @@
 }
 
 ArCoreDevice::ArCoreDevice()
-    : ArCoreDevice(
-          std::make_unique<ArCoreImplFactory>(),
-          std::make_unique<ArImageTransportFactory>(),
-          std::make_unique<vr::MailboxToSurfaceBridge>(),
-          std::make_unique<vr::ArCoreJavaUtils>(
-              base::BindRepeating(
-                  &ArCoreDevice::OnRequestInstallArModuleResult,
-                  base::Unretained(this)),  // unretained is fine for callbacks
-                                            // since ArCoreDevice owns the
-                                            // ArCoreJavaUtils instance
-              base::BindRepeating(
-                  &ArCoreDevice::OnRequestInstallSupportedArCoreResult,
-                  base::Unretained(this)))) {}
+    : ArCoreDevice(std::make_unique<ArCoreImplFactory>(),
+                   std::make_unique<ArImageTransportFactory>(),
+                   std::make_unique<vr::MailboxToSurfaceBridge>(),
+                   std::make_unique<vr::ArCoreJavaUtils>()) {}
 
 ArCoreDevice::~ArCoreDevice() {
   CallDeferredRequestSessionCallback(/*success=*/false);
   // The GL thread must be terminated since it uses our members. For example,
   // there might still be a posted Initialize() call in flight that uses
-  // arcore_install_utils_ and arcore_factory_. Ensure that the thread is
+  // arcore_session_utils_ and arcore_factory_. Ensure that the thread is
   // stopped before other members get destructed. Don't call Stop() here,
   // destruction calls Stop() and doing so twice is illegal (null pointer
   // dereference).
@@ -190,15 +181,6 @@
 
 void ArCoreDevice::RequestSessionAfterInitialization(int render_process_id,
                                                      int render_frame_id) {
-  session_state_->start_immersive_activity_callback_ =
-      base::BindOnce(&ArCoreDevice::RequestArSessionConsent, GetWeakPtr(),
-                     render_process_id, render_frame_id);
-
-  RequestArModule(render_process_id, render_frame_id);
-}
-
-void ArCoreDevice::RequestArSessionConsent(int render_process_id,
-                                           int render_frame_id) {
   auto ready_callback =
       base::BindRepeating(&ArCoreDevice::OnDrawingSurfaceReady, GetWeakPtr());
   auto touch_callback =
@@ -206,7 +188,7 @@
   auto destroyed_callback =
       base::BindOnce(&ArCoreDevice::OnDrawingSurfaceDestroyed, GetWeakPtr());
 
-  arcore_install_utils_->RequestArSession(
+  arcore_session_utils_->RequestArSession(
       render_process_id, render_frame_id, std::move(ready_callback),
       std::move(touch_callback), std::move(destroyed_callback));
 }
@@ -250,7 +232,7 @@
   DVLOG(1) << __func__;
 
   // This may be a no-op in case it's destroyed already.
-  arcore_install_utils_->DestroyDrawingSurface();
+  arcore_session_utils_->DestroyDrawingSurface();
 
   // The GL thread had initialized its context with a drawing_widget based on
   // the ArImmersiveOverlay's Surface, and the one it has is no longer valid.
@@ -276,88 +258,6 @@
   mailbox_bridge_ = nullptr;
 }
 
-void ArCoreDevice::RequestArModule(int render_process_id, int render_frame_id) {
-  DVLOG(1) << __func__;
-  if (arcore_install_utils_->ShouldRequestInstallArModule()) {
-    if (!arcore_install_utils_->CanRequestInstallArModule()) {
-      OnRequestArModuleResult(render_process_id, render_frame_id, false);
-      return;
-    }
-
-    on_request_ar_module_result_callback_ =
-        base::BindOnce(&ArCoreDevice::OnRequestArModuleResult, GetWeakPtr(),
-                       render_process_id, render_frame_id);
-    arcore_install_utils_->RequestInstallArModule(render_process_id,
-                                                  render_frame_id);
-    return;
-  }
-
-  OnRequestArModuleResult(render_process_id, render_frame_id, true);
-}
-
-void ArCoreDevice::OnRequestArModuleResult(int render_process_id,
-                                           int render_frame_id,
-                                           bool success) {
-  DVLOG(3) << __func__ << ": success=" << success;
-
-  if (!success) {
-    CallDeferredRequestSessionCallback(/*success=*/false);
-    return;
-  }
-
-  RequestArCoreInstallOrUpdate(render_process_id, render_frame_id);
-}
-
-void ArCoreDevice::RequestArCoreInstallOrUpdate(int render_process_id,
-                                                int render_frame_id) {
-  DVLOG(1) << __func__;
-  DCHECK(IsOnMainThread());
-  DCHECK(!on_request_arcore_install_or_update_result_callback_);
-
-  if (arcore_install_utils_->ShouldRequestInstallSupportedArCore()) {
-    // ARCore is not installed or requires an update. Store the callback to be
-    // processed later once installation/update is complete or got cancelled.
-    on_request_arcore_install_or_update_result_callback_ = base::BindOnce(
-        &ArCoreDevice::OnRequestArCoreInstallOrUpdateResult, GetWeakPtr());
-
-    arcore_install_utils_->RequestInstallSupportedArCore(render_process_id,
-                                                         render_frame_id);
-    return;
-  }
-
-  OnRequestArCoreInstallOrUpdateResult(true);
-}
-
-void ArCoreDevice::OnRequestArCoreInstallOrUpdateResult(bool success) {
-  DVLOG(1) << __func__;
-  DCHECK(IsOnMainThread());
-
-  if (!success) {
-    CallDeferredRequestSessionCallback(/*success=*/false);
-    return;
-  }
-
-  DCHECK(session_state_->start_immersive_activity_callback_);
-  std::move(session_state_->start_immersive_activity_callback_).Run();
-}
-
-void ArCoreDevice::OnRequestInstallArModuleResult(bool success) {
-  DVLOG(1) << __func__;
-  DCHECK(IsOnMainThread());
-
-  if (on_request_ar_module_result_callback_) {
-    std::move(on_request_ar_module_result_callback_).Run(success);
-  }
-}
-
-void ArCoreDevice::OnRequestInstallSupportedArCoreResult(bool success) {
-  DVLOG(1) << __func__;
-  DCHECK(IsOnMainThread());
-  DCHECK(on_request_arcore_install_or_update_result_callback_);
-
-  std::move(on_request_arcore_install_or_update_result_callback_).Run(success);
-}
-
 void ArCoreDevice::CallDeferredRequestSessionCallback(bool success) {
   DVLOG(1) << __func__ << " success=" << success;
   DCHECK(IsOnMainThread());
@@ -430,7 +330,7 @@
   DCHECK(IsOnMainThread());
   DCHECK(session_state_->is_arcore_gl_thread_initialized_);
 
-  if (!arcore_install_utils_->EnsureLoaded()) {
+  if (!arcore_session_utils_->EnsureLoaded()) {
     DLOG(ERROR) << "ARCore was not loaded properly.";
     OnArCoreGlInitializationComplete(false);
     return;
@@ -445,7 +345,7 @@
     PostTaskToGlThread(base::BindOnce(
         &ArCoreGl::Initialize,
         session_state_->arcore_gl_thread_->GetArCoreGl()->GetWeakPtr(),
-        arcore_install_utils_.get(), arcore_factory_.get(), drawing_widget,
+        arcore_session_utils_.get(), arcore_factory_.get(), drawing_widget,
         frame_size, rotation,
         CreateMainThreadCallback(base::BindOnce(
             &ArCoreDevice::OnArCoreGlInitializationComplete, GetWeakPtr()))));
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device.h b/chrome/browser/android/vr/arcore_device/arcore_device.h
index fc2560b..a28c944 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_device.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_device.h
@@ -22,7 +22,7 @@
 
 namespace vr {
 class MailboxToSurfaceBridge;
-class ArCoreInstallUtils;
+class ArCoreSessionUtils;
 }  // namespace vr
 
 namespace device {
@@ -37,7 +37,7 @@
       std::unique_ptr<ArCoreFactory> arcore_factory,
       std::unique_ptr<ArImageTransportFactory> ar_image_transport_factory,
       std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_to_surface_bridge,
-      std::unique_ptr<vr::ArCoreInstallUtils> arcore_install_utils);
+      std::unique_ptr<vr::ArCoreSessionUtils> arcore_session_utils);
   ArCoreDevice();
   ~ArCoreDevice() override;
 
@@ -51,9 +51,6 @@
   }
 
  private:
-  void OnRequestInstallArModuleResult(bool success);
-  void OnRequestInstallSupportedArCoreResult(bool success);
-
   // VRDeviceBase implementation
   void OnMailboxBridgeReady();
   void OnArCoreGlThreadInitialized();
@@ -88,21 +85,11 @@
 
   void RequestSessionAfterInitialization(int render_process_id,
                                          int render_frame_id);
-  void RequestArModule(int render_process_id, int render_frame_id);
-  void OnRequestArModuleResult(int render_process_id,
-                               int render_frame_id,
-                               bool success);
-  void RequestArCoreInstallOrUpdate(int render_process_id, int render_frame_id);
-  void OnRequestArCoreInstallOrUpdateResult(bool success);
   void CallDeferredRequestSessionCallback(bool success);
-  void OnRequestAndroidCameraPermissionResult(
-      base::OnceCallback<void(bool)> callback,
-      bool was_android_camera_permission_granted);
   void RequestArCoreGlInitialization(gfx::AcceleratedWidget window,
                                      int rotation,
                                      const gfx::Size& size);
   void OnArCoreGlInitializationComplete(bool success);
-  void RequestArSessionConsent(int render_process_id, int render_frame_id);
 
   void OnCreateSessionCallback(
       mojom::XRRuntime::RequestSessionCallback deferred_callback,
@@ -115,7 +102,7 @@
   std::unique_ptr<ArCoreFactory> arcore_factory_;
   std::unique_ptr<ArImageTransportFactory> ar_image_transport_factory_;
   std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge_;
-  std::unique_ptr<vr::ArCoreInstallUtils> arcore_install_utils_;
+  std::unique_ptr<vr::ArCoreSessionUtils> arcore_session_utils_;
 
   // Encapsulates data with session lifetime.
   struct SessionState {
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
index cc514c7..72706d6 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
@@ -11,9 +11,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "chrome/browser/android/vr/arcore_device/ar_image_transport.h"
-#include "chrome/browser/android/vr/arcore_device/arcore_device.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_gl.h"
-#include "chrome/browser/android/vr/arcore_device/arcore_install_utils.h"
+#include "chrome/browser/android/vr/arcore_device/arcore_session_utils.h"
 #include "chrome/browser/android/vr/arcore_device/fake_arcore.h"
 #include "chrome/browser/android/vr/mailbox_to_surface_bridge.h"
 #include "device/vr/public/mojom/vr_service.mojom.h"
@@ -82,18 +81,10 @@
   base::OnceClosure callback_;
 };
 
-class StubArCoreInstallUtils : public vr::ArCoreInstallUtils {
+class StubArCoreSessionUtils : public vr::ArCoreSessionUtils {
  public:
-  StubArCoreInstallUtils() = default;
+  StubArCoreSessionUtils() = default;
 
-  bool CanRequestInstallArModule() override { return false; }
-  bool ShouldRequestInstallArModule() override { return false; }
-
-  void RequestInstallArModule(int render_process_id,
-                              int render_frame_id) override {}
-  bool ShouldRequestInstallSupportedArCore() override { return false; }
-  void RequestInstallSupportedArCore(int render_process_id,
-                                     int render_frame_id) override {}
   void RequestArSession(
       int render_process_id,
       int render_frame_id,
@@ -148,7 +139,7 @@
   }
 
   StubMailboxToSurfaceBridge* bridge;
-  StubArCoreInstallUtils* install_utils;
+  StubArCoreSessionUtils* session_utils;
   mojom::XRFrameDataProviderPtr frame_provider;
   mojom::XREnvironmentIntegrationProviderAssociatedPtr environment_provider;
   std::unique_ptr<base::RunLoop> run_loop;
@@ -159,13 +150,13 @@
     std::unique_ptr<StubMailboxToSurfaceBridge> bridge_ptr =
         std::make_unique<StubMailboxToSurfaceBridge>();
     bridge = bridge_ptr.get();
-    std::unique_ptr<StubArCoreInstallUtils> install_utils_ptr =
-        std::make_unique<StubArCoreInstallUtils>();
-    install_utils = install_utils_ptr.get();
+    std::unique_ptr<StubArCoreSessionUtils> session_utils_ptr =
+        std::make_unique<StubArCoreSessionUtils>();
+    session_utils = session_utils_ptr.get();
     device_ = std::make_unique<ArCoreDevice>(
         std::make_unique<FakeArCoreFactory>(),
         std::make_unique<StubArImageTransportFactory>(), std::move(bridge_ptr),
-        std::move(install_utils_ptr));
+        std::move(session_utils_ptr));
   }
 
   void CreateSession() {
@@ -245,7 +236,7 @@
                                        base::BindOnce(callback, &hit_results));
   // Have to get frame data to trigger the hit-test calculation.
   GetFrameData();
-  EXPECT_TRUE(hit_results.size() > 0);
+  EXPECT_FALSE(hit_results.empty());
 }
 
 }  // namespace device
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
index 1bfb8e0..a466b51 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -20,7 +20,7 @@
 #include "base/trace_event/traced_value.h"
 #include "chrome/browser/android/vr/arcore_device/ar_image_transport.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_impl.h"
-#include "chrome/browser/android/vr/arcore_device/arcore_install_utils.h"
+#include "chrome/browser/android/vr/arcore_device/arcore_session_utils.h"
 #include "chrome/browser/android/vr/web_xr_presentation_state.h"
 #include "device/vr/public/mojom/vr_service.mojom.h"
 #include "gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.h"
@@ -119,7 +119,7 @@
   CloseBindingsIfOpen();
 }
 
-void ArCoreGl::Initialize(vr::ArCoreInstallUtils* install_utils,
+void ArCoreGl::Initialize(vr::ArCoreSessionUtils* session_utils,
                           ArCoreFactory* arcore_factory,
                           gfx::AcceleratedWidget drawing_widget,
                           const gfx::Size& frame_size,
@@ -141,7 +141,7 @@
 
   // Get the activity context.
   base::android::ScopedJavaLocalRef<jobject> application_context =
-      install_utils->GetApplicationContext();
+      session_utils->GetApplicationContext();
   if (!application_context.obj()) {
     DLOG(ERROR) << "Unable to retrieve the Java context/activity!";
     std::move(callback).Run(false);
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.h b/chrome/browser/android/vr/arcore_device/arcore_gl.h
index 0e13a647..0121a4d8 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.h
@@ -36,7 +36,7 @@
 }  // namespace gl
 
 namespace vr {
-class ArCoreInstallUtils;
+class ArCoreSessionUtils;
 class WebXrPresentationState;
 }  // namespace vr
 
@@ -63,7 +63,7 @@
   explicit ArCoreGl(std::unique_ptr<ArImageTransport> ar_image_transport);
   ~ArCoreGl() override;
 
-  void Initialize(vr::ArCoreInstallUtils* install_utils,
+  void Initialize(vr::ArCoreSessionUtils* session_utils,
                   ArCoreFactory* arcore_factory,
                   gfx::AcceleratedWidget drawing_widget,
                   const gfx::Size& frame_size,
diff --git a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc
index 111e9a3..54392cd 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc
@@ -10,11 +10,9 @@
 #include "base/android/jni_string.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/vr/ar_jni_headers/ArCoreJavaUtils_jni.h"
-#include "chrome/browser/android/vr/arcore_device/arcore_device_provider.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_shim.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
-#include "device/vr/android/arcore/arcore_device_provider_factory.h"
 
 using base::android::AttachCurrentThread;
 using base::android::ScopedJavaLocalRef;
@@ -23,29 +21,9 @@
 
 namespace {
 
-class ArCoreDeviceProviderFactoryImpl
-    : public device::ArCoreDeviceProviderFactory {
- public:
-  ArCoreDeviceProviderFactoryImpl() = default;
-  ~ArCoreDeviceProviderFactoryImpl() override = default;
-  std::unique_ptr<device::VRDeviceProvider> CreateDeviceProvider() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ArCoreDeviceProviderFactoryImpl);
-};
-
-std::unique_ptr<device::VRDeviceProvider>
-ArCoreDeviceProviderFactoryImpl::CreateDeviceProvider() {
-  return std::make_unique<device::ArCoreDeviceProvider>();
-}
-
 }  // namespace
 
-ArCoreJavaUtils::ArCoreJavaUtils(
-    base::RepeatingCallback<void(bool)> ar_module_installation_callback,
-    base::RepeatingCallback<void(bool)> ar_core_installation_callback)
-    : ar_module_installation_callback_(ar_module_installation_callback),
-      ar_core_installation_callback_(ar_core_installation_callback) {
+ArCoreJavaUtils::ArCoreJavaUtils() {
   JNIEnv* env = AttachCurrentThread();
   if (!env)
     return;
@@ -61,46 +39,6 @@
   Java_ArCoreJavaUtils_onNativeDestroy(env, j_arcore_java_utils_);
 }
 
-void ArCoreJavaUtils::OnRequestInstallSupportedArCoreResult(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj,
-    bool success) {
-  ar_core_installation_callback_.Run(success);
-}
-
-bool ArCoreJavaUtils::CanRequestInstallArModule() {
-  return Java_ArCoreJavaUtils_canRequestInstallArModule(AttachCurrentThread(),
-                                                        j_arcore_java_utils_);
-}
-
-bool ArCoreJavaUtils::ShouldRequestInstallArModule() {
-  return Java_ArCoreJavaUtils_shouldRequestInstallArModule(
-      AttachCurrentThread(), j_arcore_java_utils_);
-}
-
-void ArCoreJavaUtils::RequestInstallArModule(int render_process_id,
-                                             int render_frame_id) {
-  Java_ArCoreJavaUtils_requestInstallArModule(
-      AttachCurrentThread(), j_arcore_java_utils_,
-      getTabFromRenderer(render_process_id, render_frame_id));
-}
-
-bool ArCoreJavaUtils::ShouldRequestInstallSupportedArCore() {
-  JNIEnv* env = AttachCurrentThread();
-  return Java_ArCoreJavaUtils_shouldRequestInstallSupportedArCore(
-      env, j_arcore_java_utils_);
-}
-
-void ArCoreJavaUtils::RequestInstallSupportedArCore(int render_process_id,
-                                                    int render_frame_id) {
-  DCHECK(ShouldRequestInstallSupportedArCore());
-
-  JNIEnv* env = AttachCurrentThread();
-  Java_ArCoreJavaUtils_requestInstallSupportedArCore(
-      env, j_arcore_java_utils_,
-      getTabFromRenderer(render_process_id, render_frame_id));
-}
-
 void ArCoreJavaUtils::RequestArSession(
     int render_process_id,
     int render_frame_id,
@@ -161,13 +99,6 @@
   }
 }
 
-void ArCoreJavaUtils::OnRequestInstallArModuleResult(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj,
-    bool success) {
-  ar_module_installation_callback_.Run(success);
-}
-
 bool ArCoreJavaUtils::EnsureLoaded() {
   DCHECK(vr::IsArCoreSupported());
 
@@ -206,10 +137,4 @@
   return j_tab_android;
 }
 
-static void JNI_ArCoreJavaUtils_InstallArCoreDeviceProviderFactory(
-    JNIEnv* env) {
-  device::ArCoreDeviceProviderFactory::Install(
-      std::make_unique<ArCoreDeviceProviderFactoryImpl>());
-}
-
 }  // namespace vr
diff --git a/chrome/browser/android/vr/arcore_device/arcore_java_utils.h b/chrome/browser/android/vr/arcore_device/arcore_java_utils.h
index 5a5afe5..9e9ac15 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_java_utils.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_java_utils.h
@@ -11,39 +11,26 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/android/vr/arcore_device/arcore_install_utils.h"
+#include "chrome/browser/android/vr/arcore_device/arcore_session_utils.h"
 
 namespace vr {
 
-class ArCoreJavaUtils : public ArCoreInstallUtils {
+class ArCoreJavaUtils : public ArCoreSessionUtils {
  public:
-  explicit ArCoreJavaUtils(
-      base::RepeatingCallback<void(bool)> ar_module_installation_callback,
-      base::RepeatingCallback<void(bool)> ar_core_installation_callback);
+  ArCoreJavaUtils();
   ~ArCoreJavaUtils() override;
-  bool ShouldRequestInstallArModule() override;
-  bool CanRequestInstallArModule() override;
-  void RequestInstallArModule(int render_process_id,
-                              int render_frame_id) override;
-  bool ShouldRequestInstallSupportedArCore() override;
-  void RequestInstallSupportedArCore(int render_process_id,
-                                     int render_frame_id) override;
+
+  // ArCoreSessionUtils:
   void RequestArSession(int render_process_id,
                         int render_frame_id,
                         SurfaceReadyCallback ready_callback,
                         SurfaceTouchCallback touch_callback,
                         SurfaceDestroyedCallback destroyed_callback) override;
   void DestroyDrawingSurface() override;
+  bool EnsureLoaded() override;
+  base::android::ScopedJavaLocalRef<jobject> GetApplicationContext() override;
 
   // Methods called from the Java side.
-  void OnRequestInstallArModuleResult(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      bool success);
-  void OnRequestInstallSupportedArCoreResult(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      bool success);
   void OnDrawingSurfaceReady(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
@@ -60,17 +47,11 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
-  bool EnsureLoaded() override;
-  base::android::ScopedJavaLocalRef<jobject> GetApplicationContext() override;
-
  private:
   base::android::ScopedJavaLocalRef<jobject> getTabFromRenderer(
       int render_process_id,
       int render_frame_id);
 
-  base::RepeatingCallback<void(bool)> ar_module_installation_callback_;
-  base::RepeatingCallback<void(bool)> ar_core_installation_callback_;
-
   base::android::ScopedJavaGlobalRef<jobject> j_arcore_java_utils_;
 
   SurfaceReadyCallback surface_ready_callback_;
diff --git a/chrome/browser/android/vr/arcore_device/arcore_install_utils.h b/chrome/browser/android/vr/arcore_device/arcore_session_utils.h
similarity index 64%
rename from chrome/browser/android/vr/arcore_device/arcore_install_utils.h
rename to chrome/browser/android/vr/arcore_device/arcore_session_utils.h
index f115698..1573fbe 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_install_utils.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_session_utils.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_INSTALL_UTILS_H_
-#define CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_INSTALL_UTILS_H_
+#ifndef CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_SESSION_UTILS_H_
+#define CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_SESSION_UTILS_H_
 
 #include "base/android/scoped_java_ref.h"
 #include "base/memory/weak_ptr.h"
@@ -30,18 +30,9 @@
     base::RepeatingCallback<void(bool touching, const gfx::PointF& location)>;
 using SurfaceDestroyedCallback = base::OnceClosure;
 
-class ArCoreInstallUtils {
+class ArCoreSessionUtils {
  public:
-  virtual ~ArCoreInstallUtils() = default;
-  // Returns true if AR module installation is supported, false otherwise.
-  virtual bool CanRequestInstallArModule() = 0;
-  // Returns true if AR module is not installed, false otherwise.
-  virtual bool ShouldRequestInstallArModule() = 0;
-  virtual void RequestInstallArModule(int render_process_id,
-                                      int render_frame_id) = 0;
-  virtual bool ShouldRequestInstallSupportedArCore() = 0;
-  virtual void RequestInstallSupportedArCore(int render_process_id,
-                                             int render_frame_id) = 0;
+  virtual ~ArCoreSessionUtils() = default;
   virtual bool EnsureLoaded() = 0;
   virtual base::android::ScopedJavaLocalRef<jobject>
   GetApplicationContext() = 0;
@@ -56,4 +47,4 @@
 
 }  // namespace vr
 
-#endif  // CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_INSTALL_UTILS_H_
+#endif  // CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_SESSION_UTILS_H_
diff --git a/chrome/browser/android/vr/vr_module_provider.cc b/chrome/browser/android/vr/vr_module_provider.cc
index 1004ae4..92abcf8 100644
--- a/chrome/browser/android/vr/vr_module_provider.cc
+++ b/chrome/browser/android/vr/vr_module_provider.cc
@@ -88,7 +88,7 @@
 static void JNI_VrModuleProvider_Init(JNIEnv* env) {
   GvrConsentHelper::SetInstance(std::make_unique<vr::GvrConsentHelperImpl>());
 #if BUILDFLAG(ENABLE_ARCORE)
-  ArcoreConsentPromptInterface::SetInstance(new ArcoreConsentPrompt());
+  ArCoreConsentPromptInterface::SetInstance(new ArCoreConsentPrompt());
 #endif
 }
 
diff --git a/chrome/browser/autofill/autofill_keyboard_accessory_adapter.cc b/chrome/browser/autofill/autofill_keyboard_accessory_adapter.cc
index 4caa854..35843fa 100644
--- a/chrome/browser/autofill/autofill_keyboard_accessory_adapter.cc
+++ b/chrome/browser/autofill/autofill_keyboard_accessory_adapter.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
 #include "chrome/browser/ui/autofill/autofill_popup_layout_model.h"
 #include "components/autofill/core/browser/ui/popup_item_ids.h"
@@ -17,6 +18,22 @@
 
 namespace autofill {
 
+constexpr base::char16 kLabelSeparator = ' ';
+constexpr size_t kMaxBulletCount = 8;
+
+namespace {
+base::string16 CreateLabel(const Suggestion& suggestion) {
+  base::string16 password =
+      suggestion.additional_label.substr(0, kMaxBulletCount);
+  // The label contains the signon_realm or is empty. The additional_label can
+  // never be empty since it must contain a password.
+  if (suggestion.label.empty())
+    return password;
+  return suggestion.label + kLabelSeparator + password;
+}
+
+}  // namespace
+
 AutofillKeyboardAccessoryAdapter::AutofillKeyboardAccessoryAdapter(
     AutofillPopupController* controller,
     unsigned int animation_duration_millis,
@@ -49,14 +66,19 @@
   DCHECK(controller_) << "Call OnSuggestionsChanged only from its owner!";
   DCHECK(view_) << "OnSuggestionsChanged called before a View was set!";
 
+  labels_.clear();
   front_element_ = base::nullopt;
   for (int i = 0; i < GetLineCount(); ++i) {
     const Suggestion& suggestion = controller_->GetSuggestionAt(i);
     if (suggestion.frontend_id != POPUP_ITEM_ID_CLEAR_FORM &&
-        suggestion.frontend_id != POPUP_ITEM_ID_CREATE_HINT)
+        suggestion.frontend_id != POPUP_ITEM_ID_CREATE_HINT) {
+      labels_.push_back(CreateLabel(suggestion));
       continue;
+    }
     DCHECK(!front_element_.has_value()) << "Additional front item at: " << i;
     front_element_ = base::Optional<int>(i);
+    // If there is a special popup item, just reuse the previously used label.
+    labels_.push_back(controller_->GetElidedLabelAt(i));
   }
 
   view_->Show();
@@ -75,24 +97,21 @@
 
 const autofill::Suggestion& AutofillKeyboardAccessoryAdapter::GetSuggestionAt(
     int row) const {
-  DCHECK(controller_) << "Call OnSuggestionsChanged only from its owner!";
+  DCHECK(controller_) << "Call GetSuggestionAt only from its owner!";
   return controller_->GetSuggestionAt(OffsetIndexFor(row));
 }
 
 const base::string16& AutofillKeyboardAccessoryAdapter::GetElidedValueAt(
     int row) const {
-  DCHECK(controller_) << "Call OnSuggestionsChanged only from its owner!";
+  DCHECK(controller_) << "Call GetElidedValueAt only from its owner!";
   return controller_->GetElidedValueAt(OffsetIndexFor(row));
 }
 
 const base::string16& AutofillKeyboardAccessoryAdapter::GetElidedLabelAt(
     int row) const {
-  DCHECK(controller_) << "Call OnSuggestionsChanged only from its owner!";
-  const base::string16& label =
-      controller_->GetElidedLabelAt(OffsetIndexFor(row));
-  if (label.empty())
-    return GetSuggestionAt(row).additional_label;
-  return label;
+  DCHECK(controller_) << "Call GetElidedLabelAt only from its owner!";
+  DCHECK(static_cast<size_t>(row) < labels_.size());
+  return labels_[OffsetIndexFor(row)];
 }
 
 bool AutofillKeyboardAccessoryAdapter::GetRemovalConfirmationText(
diff --git a/chrome/browser/autofill/autofill_keyboard_accessory_adapter.h b/chrome/browser/autofill/autofill_keyboard_accessory_adapter.h
index 8ad5806..c8b597d 100644
--- a/chrome/browser/autofill/autofill_keyboard_accessory_adapter.h
+++ b/chrome/browser/autofill/autofill_keyboard_accessory_adapter.h
@@ -100,6 +100,9 @@
   AutofillPopupController* controller_;  // weak.
   std::unique_ptr<AutofillKeyboardAccessoryAdapter::AccessoryView> view_;
 
+  // The labels to be used for the input chips.
+  std::vector<base::string16> labels_;
+
   // If 0, don't animate suggestion view.
   const unsigned int animation_duration_millis_;
 
diff --git a/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc b/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc
index 12ef283..a901596 100644
--- a/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc
+++ b/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc
@@ -5,6 +5,7 @@
 #include <cstddef>
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -51,13 +52,20 @@
   DISALLOW_COPY_AND_ASSIGN(MockAccessoryView);
 };
 
+Suggestion createPasswordEntry(std::string password,
+                               std::string username,
+                               std::string psl_origin) {
+  Suggestion s(/*value=*/username, /*label=*/psl_origin, /*icon=*/"",
+               PopupItemId::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY);
+  s.additional_label = ASCIIToUTF16(password);
+  return s;
+}
+
 std::vector<Suggestion> createSuggestions() {
   std::vector<Suggestion> suggestions = {
-      Suggestion("*", "A", "", PopupItemId::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY),
-      Suggestion("**", "", "", PopupItemId::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY),
-      Suggestion("***", "C", "",
-                 PopupItemId::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)};
-  suggestions[1].additional_label = ASCIIToUTF16("B");
+      createPasswordEntry("****************", "Alf", ""),
+      createPasswordEntry("****************", "Berta", "psl.origin.eg"),
+      createPasswordEntry("***", "Carl", "")};
   return suggestions;
 }
 
@@ -174,14 +182,23 @@
 }
 
 TEST_F(AutofillKeyboardAccessoryAdapterTest, UseAdditionalLabelForElidedLabel) {
-  controller()->set_suggestions(createSuggestions());
+  controller()->set_suggestions(createSuggestions(/*clearItemOffset=*/1));
   NotifyAboutSuggestions();
 
-  // If there is a label, use it.
-  EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(0), ASCIIToUTF16("A"));
+  // The 1st item is usually not visible (something like clear form) and has an
+  // empty label. But it needs to be handled since UI might ask for it anyway.
+  EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(0), base::string16());
+
+  // If there is a label, use it but cap at 8 bullets.
+  EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(1),
+            ASCIIToUTF16("********"));
 
   // If the label is empty, use the additional label:
-  EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(1), ASCIIToUTF16("B"));
+  EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(2),
+            ASCIIToUTF16("psl.origin.eg ********"));
+
+  // If the password has less than 8 bullets, show the exact amount.
+  EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(3), ASCIIToUTF16("***"));
 }
 
 TEST_F(AutofillKeyboardAccessoryAdapterTest, ProvideReorderedSuggestions) {
diff --git a/chrome/browser/bookmarks/OWNERS b/chrome/browser/bookmarks/OWNERS
index 90b3e80..6cfd65c 100644
--- a/chrome/browser/bookmarks/OWNERS
+++ b/chrome/browser/bookmarks/OWNERS
@@ -1 +1,2 @@
 sky@chromium.org
+# COMPONENT: UI>Browser>Bookmarks
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
index e9b4ad7..b78c4e2 100644
--- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
+++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
@@ -826,11 +826,13 @@
     const std::string& principal_name) {
   // TODO(https://crbug.com/952245): Right now, the reauth dialog is tied to the
   // settings. Consider creating a standalone reauth dialog.
-  kerberos_ticket_expiry_notification::Close(primary_profile_);
   chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
       primary_profile_,
       chrome::kKerberosAccountsSubPage + std::string("?kerberos_reauth=") +
           net::EscapeQueryParamValue(principal_name, false /* use_plus */));
+
+  // Close last! |principal_name| is owned by the notification.
+  kerberos_ticket_expiry_notification::Close(primary_profile_);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc
index 7452adda..b1c6a02 100644
--- a/chrome/browser/chromeos/login/oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_browsertest.cc
@@ -20,6 +20,10 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/constants/chromeos_switches.h"
+#include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
+#include "chromeos/dbus/cryptohome/key.pb.h"
+#include "chromeos/dbus/cryptohome/rpc.pb.h"
+#include "chromeos/login/auth/cryptohome_key_constants.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/known_user.h"
 #include "components/user_manager/user.h"
@@ -81,6 +85,9 @@
       chrome::NOTIFICATION_SESSION_STARTED,
       content::NotificationService::AllSources());
 
+  // Make the MountEx cryptohome call fail iff the |create| field is missing,
+  // which simulates the real cryptohomed's behavior for the new user mount.
+  FakeCryptohomeClient::Get()->set_mount_create_required(true);
   LoginDisplayHost::default_host()
       ->GetOobeUI()
       ->GetView<GaiaScreenHandler>()
@@ -95,6 +102,23 @@
           ->GetAccountId();
   EXPECT_FALSE(
       user_manager::known_user::GetIsUsingSAMLPrincipalsAPI(account_id));
+
+  // Verify the parameters that were passed to the latest MountEx call.
+  const cryptohome::AuthorizationRequest& cryptohome_auth =
+      FakeCryptohomeClient::Get()->get_last_mount_authentication();
+  EXPECT_EQ(cryptohome::KeyData::KEY_TYPE_PASSWORD,
+            cryptohome_auth.key().data().type());
+  EXPECT_TRUE(cryptohome_auth.key().data().label().empty());
+  EXPECT_FALSE(cryptohome_auth.key().secret().empty());
+  const cryptohome::MountRequest& last_mount_request =
+      FakeCryptohomeClient::Get()->get_last_mount_request();
+  ASSERT_TRUE(last_mount_request.has_create());
+  ASSERT_EQ(1, last_mount_request.create().keys_size());
+  EXPECT_EQ(cryptohome::KeyData::KEY_TYPE_PASSWORD,
+            last_mount_request.create().keys(0).data().type());
+  EXPECT_EQ(kCryptohomeGaiaKeyLabel,
+            last_mount_request.create().keys(0).data().label());
+  EXPECT_FALSE(last_mount_request.create().keys(0).secret().empty());
 }
 
 IN_PROC_BROWSER_TEST_F(OobeTest, Accelerator) {
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
index 8a7a72d..5300fb3 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
@@ -32,6 +32,7 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile_downloader.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/chrome_paths.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -39,6 +40,7 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/user_manager/user_image/user_image.h"
 #include "components/user_manager/user_manager.h"
+#include "content/public/browser/storage_partition.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/chromeos/resources/grit/ui_chromeos_resources.h"
 #include "ui/gfx/image/image_skia.h"
@@ -791,8 +793,16 @@
   return GetCurrentUserImageSize();
 }
 
-Profile* UserImageManagerImpl::GetBrowserProfile() {
-  return ProfileHelper::Get()->GetProfileByUserUnsafe(GetUser());
+identity::IdentityManager* UserImageManagerImpl::GetIdentityManager() {
+  return IdentityManagerFactory::GetForProfile(
+      ProfileHelper::Get()->GetProfileByUserUnsafe(GetUser()));
+}
+
+network::mojom::URLLoaderFactory* UserImageManagerImpl::GetURLLoaderFactory() {
+  return content::BrowserContext::GetDefaultStoragePartition(
+             ProfileHelper::Get()->GetProfileByUserUnsafe(GetUser()))
+      ->GetURLLoaderFactoryForBrowserProcess()
+      .get();
 }
 
 std::string UserImageManagerImpl::GetCachedPictureURL() const {
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h
index 10ac558..e94a364 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h
@@ -94,7 +94,8 @@
   // ProfileDownloaderDelegate:
   bool NeedsProfilePicture() const override;
   int GetDesiredImageSideLength() const override;
-  Profile* GetBrowserProfile() override;
+  identity::IdentityManager* GetIdentityManager() override;
+  network::mojom::URLLoaderFactory* GetURLLoaderFactory() override;
   std::string GetCachedPictureURL() const override;
   bool IsPreSignin() const override;
   void OnProfileDownloadSuccess(ProfileDownloader* downloader) override;
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index 24d5ad4..51b4ed8 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -47,6 +48,7 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/browser/chromeos/system/timezone_util.h"
 #include "chrome/browser/policy/device_management_service_configuration.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/attestation/attestation_flow.h"
 #include "chromeos/constants/chromeos_paths.h"
@@ -248,9 +250,12 @@
   device_cloud_external_data_policy_handlers_.emplace_back(
       std::make_unique<policy::DeviceWallpaperImageExternalDataHandler>(
           local_state, GetPolicyService()));
-  device_cloud_external_data_policy_handlers_.emplace_back(
-      std::make_unique<policy::DeviceWilcoDtcConfigurationExternalDataHandler>(
-          GetPolicyService()));
+  if (base::FeatureList::IsEnabled(::features::kWilcoDtc)) {
+    device_cloud_external_data_policy_handlers_.emplace_back(
+        std::make_unique<
+            policy::DeviceWilcoDtcConfigurationExternalDataHandler>(
+            GetPolicyService()));
+  }
 }
 
 void BrowserPolicyConnectorChromeOS::PreShutdown() {
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_store.cc b/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
index 4562b5c..3c8f340 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
@@ -211,7 +211,7 @@
 
   auto validator = std::make_unique<UserCloudPolicyValidator>(
       std::move(policy_response), background_task_runner());
-  validator->ValidateUsername(account_id_, false);
+  validator->ValidateUsername(account_id_);
   validator->ValidatePolicyType(dm_protocol::kChromePublicAccountPolicyType);
   // The timestamp is verified when storing a new policy downloaded from the
   // server but not when loading a cached policy from disk.
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc
index 4b137e7..0403f9f 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc
@@ -34,18 +34,14 @@
 
 void DeviceWilcoDtcConfigurationExternalDataHandler::
     OnDeviceExternalDataCleared(const std::string& policy) {
-  auto* wilco_manager = GetWilcoDtcSupportdManager();
-  if (wilco_manager)
-    wilco_manager->SetConfigurationData(nullptr);
+  GetWilcoDtcSupportdManager()->SetConfigurationData(nullptr);
 }
 
 void DeviceWilcoDtcConfigurationExternalDataHandler::
     OnDeviceExternalDataFetched(const std::string& policy,
                                 std::unique_ptr<std::string> data,
                                 const base::FilePath& file_path) {
-  auto* wilco_manager = GetWilcoDtcSupportdManager();
-  if (wilco_manager)
-    wilco_manager->SetConfigurationData(std::move(data));
+  GetWilcoDtcSupportdManager()->SetConfigurationData(std::move(data));
 }
 
 void DeviceWilcoDtcConfigurationExternalDataHandler::Shutdown() {
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc b/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc
new file mode 100644
index 0000000..4af290a
--- /dev/null
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc
@@ -0,0 +1,144 @@
+// Copyright 2019 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 <cstdint>
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part_chromeos.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
+#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
+#include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/policy/core/common/external_data_fetcher.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_namespace.h"
+#include "components/policy/core/common/policy_service.h"
+#include "components/policy/policy_constants.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+// Class used to test DeviceWilcoDtcConfigurationExternalPolicyHandler depending
+// on the feature flag.
+class DeviceWilcoDtcConfigurationExternalPolicyHandlerTest
+    : public DevicePolicyCrosBrowserTest,
+      public ::testing::WithParamInterface<bool> {
+ public:
+  DeviceWilcoDtcConfigurationExternalPolicyHandlerTest() {
+    feature_list_.InitWithFeatureState(::features::kWilcoDtc,
+                                       IsWilcoDtcFeatureEnabled());
+  }
+  ~DeviceWilcoDtcConfigurationExternalPolicyHandlerTest() override = default;
+
+ protected:
+  void SetUpOnMainThread() override {
+    ASSERT_TRUE(embedded_test_server()->Start());
+    DevicePolicyCrosBrowserTest::SetUpOnMainThread();
+
+    policy_change_waiting_run_loop_ = std::make_unique<base::RunLoop>();
+
+    BrowserPolicyConnectorChromeOS* policy_connector =
+        g_browser_process->platform_part()->browser_policy_connector_chromeos();
+    ASSERT_TRUE(policy_connector);
+    policy_service_ = policy_connector->GetPolicyService();
+    ASSERT_TRUE(
+        policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
+    policy_change_registrar_ = std::make_unique<PolicyChangeRegistrar>(
+        policy_service_, PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
+    policy_change_registrar_->Observe(
+        policy::key::kDeviceWilcoDtcConfiguration,
+        base::BindRepeating(
+            &DeviceWilcoDtcConfigurationExternalPolicyHandlerTest ::
+                PolicyChangedCallback,
+            base::Unretained(this)));
+  }
+
+  void TearDownOnMainThread() override {
+    policy_change_registrar_.reset();
+    DevicePolicyCrosBrowserTest::TearDownOnMainThread();
+  }
+
+  bool IsWilcoDtcFeatureEnabled() { return GetParam(); }
+
+  void SetDeviceWilcoDtcConfigurationExternalData(const std::string& policy) {
+    device_policy()
+        ->payload()
+        .mutable_device_wilco_dtc_configuration()
+        ->set_device_wilco_dtc_configuration(policy);
+    RefreshDevicePolicy();
+    WaitUntilPolicyChanged();
+  }
+
+  void FetchExternalData() {
+    const PolicyMap& policies = policy_service_->GetPolicies(
+        PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
+    const PolicyMap::Entry* policy_entry =
+        policies.Get(policy::key::kDeviceWilcoDtcConfiguration);
+    EXPECT_TRUE(policy_entry);
+    EXPECT_TRUE(policy_entry->external_data_fetcher);
+
+    base::RunLoop run_loop;
+    std::unique_ptr<std::string> fetched_external_data;
+    base::FilePath file_path;
+    policy_entry->external_data_fetcher->Fetch(base::BindOnce(
+        [](base::OnceClosure quit_closure, std::string* external_data,
+           std::unique_ptr<std::string> data, const base::FilePath& path) {
+          *external_data = (data ? *data : "");
+          std::move(quit_closure).Run();
+        },
+        run_loop.QuitClosure(), &external_data_));
+    run_loop.Run();
+  }
+
+  const std::string& external_data() { return external_data_; }
+
+ private:
+  void PolicyChangedCallback(const base::Value* old_value,
+                             const base::Value* new_value) {
+    policy_change_waiting_run_loop_->Quit();
+  }
+
+  void WaitUntilPolicyChanged() {
+    policy_change_waiting_run_loop_->Run();
+    policy_change_waiting_run_loop_ = std::make_unique<base::RunLoop>();
+  }
+
+  base::test::ScopedFeatureList feature_list_;
+  std::unique_ptr<base::RunLoop> policy_change_waiting_run_loop_;
+  PolicyService* policy_service_ = nullptr;  // owned by BrowserPolicyConnector.
+  std::unique_ptr<PolicyChangeRegistrar> policy_change_registrar_;
+  std::string external_data_;
+};
+
+// Test that nothing crashes and WilcoDtcConfiguration is successfully passed
+// to WilcoDtcSupportdManager if the feature is enabled.
+IN_PROC_BROWSER_TEST_P(DeviceWilcoDtcConfigurationExternalPolicyHandlerTest,
+                       FetchExternalData) {
+  EXPECT_EQ(IsWilcoDtcFeatureEnabled(),
+            chromeos::WilcoDtcSupportdManager::Get() != nullptr);
+  SetDeviceWilcoDtcConfigurationExternalData(test::ConstructExternalDataPolicy(
+      *embedded_test_server(), "policy/wilco_dtc_configuration.json"));
+  FetchExternalData();
+  if (IsWilcoDtcFeatureEnabled()) {
+    EXPECT_EQ(external_data(), chromeos::WilcoDtcSupportdManager::Get()
+                                   ->GetConfigurationDataForTesting());
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+                         DeviceWilcoDtcConfigurationExternalPolicyHandlerTest,
+                         testing::Bool());
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/system_log_uploader.cc b/chrome/browser/chromeos/policy/system_log_uploader.cc
index 9e06dd7..df74942 100644
--- a/chrome/browser/chromeos/policy/system_log_uploader.cc
+++ b/chrome/browser/chromeos/policy/system_log_uploader.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "components/feedback/anonymizer_tool.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/user_manager/user_manager.h"
@@ -130,7 +131,8 @@
 // as pairs (file name, data) and returns. Called on blocking thread.
 std::unique_ptr<SystemLogUploader::SystemLogs> ReadFiles() {
   auto system_logs = std::make_unique<SystemLogUploader::SystemLogs>();
-  feedback::AnonymizerTool anonymizer;
+  feedback::AnonymizerTool anonymizer(
+      extension_misc::kBuiltInFirstPartyExtensionIds);
   for (const char* file_path : kSystemLogFileNames) {
     if (!base::PathExists(base::FilePath(file_path)))
       continue;
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index d13a4b0..c4afed0 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -197,12 +197,6 @@
     hardware_keyboard_id = "xkb:us::eng";  // only for testing.
   }
 
-  registry->RegisterBooleanPref(ash::prefs::kKioskNextShellEligible,
-                                /*default_value=*/false);
-
-  registry->RegisterBooleanPref(ash::prefs::kKioskNextShellEnabled,
-                                /*default_value=*/false, PrefRegistry::PUBLIC);
-
   registry->RegisterBooleanPref(prefs::kPerformanceTracingEnabled, false);
 
   // This pref is device specific and must not be synced.
diff --git a/chrome/browser/chromeos/ui/idle_app_name_notification_view.cc b/chrome/browser/chromeos/ui/idle_app_name_notification_view.cc
index f91bb3f..c9990e0 100644
--- a/chrome/browser/chromeos/ui/idle_app_name_notification_view.cc
+++ b/chrome/browser/chromeos/ui/idle_app_name_notification_view.cc
@@ -65,7 +65,7 @@
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
   params.accept_events = false;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.delegate = delegate;
   params.bounds = bounds;
   ash_util::SetupWidgetInitParamsForContainer(
diff --git a/chrome/browser/chromeos/ui/kiosk_external_update_notification.cc b/chrome/browser/chromeos/ui/kiosk_external_update_notification.cc
index e05a253..3fc79b8 100644
--- a/chrome/browser/chromeos/ui/kiosk_external_update_notification.cc
+++ b/chrome/browser/chromeos/ui/kiosk_external_update_notification.cc
@@ -133,7 +133,7 @@
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
   params.accept_events = false;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.delegate = view_;
   params.bounds = bounds;
   // The notification is shown on the primary display.
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.cc
index bfcb571..7e1e27e 100644
--- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.cc
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
+#include "base/strings/string_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h"
 #include "chrome/browser/net/system_network_context_manager.h"
@@ -126,6 +127,11 @@
   wilco_dtc_supportd_mojo_proxy->NotifyConfigurationDataChanged();
 }
 
+const std::string& WilcoDtcSupportdManager::GetConfigurationDataForTesting()
+    const {
+  return configuration_data_ ? *configuration_data_ : base::EmptyString();
+}
+
 void WilcoDtcSupportdManager::OnSessionStateChanged() {
   session_manager::SessionState session_state =
       session_manager::SessionManager::Get()->session_state();
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h
index 547dd4d..b3ffd4c 100644
--- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h
@@ -51,6 +51,7 @@
   // The nullptr should be passed to clear it.
   // Notifies the |wilco_dtc_supportd_bridge_| if it is created.
   void SetConfigurationData(std::unique_ptr<std::string> data);
+  const std::string& GetConfigurationDataForTesting() const;
 
  private:
   // session_manager::SessionManagerObserver override:
diff --git a/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc
index 1b8de63..33f9d42 100644
--- a/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc
+++ b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc
@@ -33,8 +33,6 @@
 #include "chrome/browser/chromeos/system_logs/single_log_file_log_source.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/ash/kiosk_next_shell_client.h"
 #include "components/feedback/feedback_util.h"
 #include "components/feedback/system_logs/system_logs_source.h"
 #include "extensions/browser/extension_system.h"
@@ -200,8 +198,12 @@
   constexpr bool scrub = true;
 
   if (system_logs::ContainsIwlwifiLogs(feedback_data->sys_info())) {
+    // TODO (jkardatzke): Modify this so that we are using the same instance of
+    // the anonymizer for the rest of the logs.
+    // We can pass null for the 1st party IDs since we are just anonymizing
+    // wifi data here.
     system_logs::SystemLogsFetcher* fetcher =
-        new system_logs::SystemLogsFetcher(scrub);
+        new system_logs::SystemLogsFetcher(scrub, nullptr);
     fetcher->AddSource(std::make_unique<system_logs::IwlwifiDumpLogSource>());
     fetcher->Fetch(base::BindOnce(&OnFetchedExtraLogs, feedback_data,
                                   std::move(callback)));
@@ -221,11 +223,6 @@
 api::feedback_private::LandingPageType
 ChromeFeedbackPrivateDelegate::GetLandingPageType(
     const feedback::FeedbackData& feedback_data) const {
-  if (KioskNextShellClient::Get() &&
-      KioskNextShellClient::Get()->has_launched()) {
-    return api::feedback_private::LANDING_PAGE_TYPE_NOLANDINGPAGE;
-  }
-
   // Googlers using eve get a custom landing page.
   if (!feedback_util::IsGoogleEmail(feedback_data.user_email()))
     return api::feedback_private::LANDING_PAGE_TYPE_NORMAL;
diff --git a/chrome/browser/extensions/api/resources_private/resources_private_api.cc b/chrome/browser/extensions/api/resources_private/resources_private_api.cc
index ab229e48..6c5eba3 100644
--- a/chrome/browser/extensions/api/resources_private/resources_private_api.cc
+++ b/chrome/browser/extensions/api/resources_private/resources_private_api.cc
@@ -20,7 +20,10 @@
 
 #if BUILDFLAG(ENABLE_PDF)
 #include "pdf/pdf_features.h"
-#endif
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/ui/login_display_host.h"
+#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(ENABLE_PDF)
 
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
 #include "chrome/common/chrome_features.h"
@@ -125,7 +128,14 @@
   dict->SetKey("pdfAnnotationsEnabled",
                base::Value(base::FeatureList::IsEnabled(
                    chrome_pdf::features::kPDFAnnotations)));
-#endif
+
+  bool enable_printing = true;
+#if defined(OS_CHROMEOS)
+  // For Chrome OS, enable printing only if we are not at OOBE.
+  enable_printing = !chromeos::LoginDisplayHost::default_host();
+#endif  // defined(OS_CHROMEOS)
+  dict->SetKey("printingEnabled", base::Value(enable_printing));
+#endif  // BUILDFLAG(ENABLE_PDF)
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
   dict->SetKey("newPrintPreviewLayoutEnabled",
                base::Value(base::FeatureList::IsEnabled(
diff --git a/chrome/browser/extensions/api/tabs/app_base_window.cc b/chrome/browser/extensions/api/tabs/app_base_window.cc
index 324756e..fd82bdb 100644
--- a/chrome/browser/extensions/api/tabs/app_base_window.cc
+++ b/chrome/browser/extensions/api/tabs/app_base_window.cc
@@ -105,12 +105,12 @@
   GetBaseWindow()->FlashFrame(flash);
 }
 
-bool AppBaseWindow::IsAlwaysOnTop() const {
-  return GetBaseWindow()->IsAlwaysOnTop();
+ui::ZOrderLevel AppBaseWindow::GetZOrderLevel() const {
+  return GetBaseWindow()->GetZOrderLevel();
 }
 
-void AppBaseWindow::SetAlwaysOnTop(bool always_on_top) {
-  GetBaseWindow()->SetAlwaysOnTop(always_on_top);
+void AppBaseWindow::SetZOrderLevel(ui::ZOrderLevel level) {
+  GetBaseWindow()->SetZOrderLevel(level);
 }
 
 NativeAppWindow* AppBaseWindow::GetBaseWindow() const {
diff --git a/chrome/browser/extensions/api/tabs/app_base_window.h b/chrome/browser/extensions/api/tabs/app_base_window.h
index d9ccfb5..7e17b85 100644
--- a/chrome/browser/extensions/api/tabs/app_base_window.h
+++ b/chrome/browser/extensions/api/tabs/app_base_window.h
@@ -45,8 +45,8 @@
   void Restore() override;
   void SetBounds(const gfx::Rect& bounds) override;
   void FlashFrame(bool flash) override;
-  bool IsAlwaysOnTop() const override;
-  void SetAlwaysOnTop(bool always_on_top) override;
+  ui::ZOrderLevel GetZOrderLevel() const override;
+  void SetZOrderLevel(ui::ZOrderLevel order) override;
 
   NativeAppWindow* GetBaseWindow() const;
 
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
index 887e936..b06f975 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -19,7 +19,6 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_browser_main.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/download/download_browsertest.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
@@ -67,39 +66,36 @@
 // |script| in the last committed RVH and resumes the load when a URL ending in
 // |until_url_suffix| commits. This class expects |script| to trigger the load
 // of an URL ending in |until_url_suffix|.
-class DelayLoadStartAndExecuteJavascript
-    : public content::NotificationObserver,
-      public content::WebContentsObserver {
+class DelayLoadStartAndExecuteJavascript : public TabStripModelObserver,
+                                           public content::WebContentsObserver {
  public:
-  DelayLoadStartAndExecuteJavascript(
-      const GURL& delay_url,
-      const std::string& script,
-      const std::string& until_url_suffix)
+  DelayLoadStartAndExecuteJavascript(Browser* browser,
+                                     const GURL& delay_url,
+                                     const std::string& script,
+                                     const std::string& until_url_suffix)
       : content::WebContentsObserver(),
         delay_url_(delay_url),
         until_url_suffix_(until_url_suffix),
-        script_(script),
-        has_user_gesture_(false),
-        script_was_executed_(false),
-        rfh_(nullptr) {
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_TAB_ADDED,
-                   content::NotificationService::AllSources());
+        script_(script) {
+    tab_strip_observer_.Add(browser->tab_strip_model());
   }
+
   ~DelayLoadStartAndExecuteJavascript() override {}
 
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override {
-    if (type != chrome::NOTIFICATION_TAB_ADDED) {
-      NOTREACHED();
+  // TabStripModelObserver:
+  void OnTabStripModelChanged(
+      TabStripModel* tab_strip_model,
+      const TabStripModelChange& change,
+      const TabStripSelectionChange& selection) override {
+    if (change.type() != TabStripModelChange::kInserted)
       return;
-    }
+
     content::WebContentsObserver::Observe(
-        content::Details<content::WebContents>(details).ptr());
-    registrar_.RemoveAll();
+        change.GetInsert()->contents[0].contents);
+    tab_strip_observer_.RemoveAll();
   }
 
+  // WebContentsObserver:
   void DidStartNavigation(
       content::NavigationHandle* navigation_handle) override {
     if (navigation_handle->GetURL() != delay_url_ || !rfh_)
@@ -128,7 +124,7 @@
     if (script_was_executed_ &&
         base::EndsWith(navigation_handle->GetURL().spec(), until_url_suffix_,
                        base::CompareCase::SENSITIVE)) {
-      content::WebContentsObserver::Observe(NULL);
+      content::WebContentsObserver::Observe(nullptr);
       if (throttle_)
         throttle_->Unblock();
     }
@@ -168,16 +164,16 @@
     bool throttled_ = false;
   };
 
-  content::NotificationRegistrar registrar_;
-
   base::WeakPtr<WillStartRequestObserverThrottle> throttle_;
 
+  ScopedObserver<TabStripModel, TabStripModelObserver> tab_strip_observer_{
+      this};
   GURL delay_url_;
   std::string until_url_suffix_;
   std::string script_;
-  bool has_user_gesture_;
-  bool script_was_executed_;
-  content::RenderFrameHost* rfh_;
+  bool has_user_gesture_ = false;
+  bool script_was_executed_ = false;
+  content::RenderFrameHost* rfh_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(DelayLoadStartAndExecuteJavascript);
 };
@@ -499,13 +495,11 @@
 
   // See crossProcess/d.html.
   DelayLoadStartAndExecuteJavascript call_script(
-      embedded_test_server()->GetURL("/test1"),
-      "navigate2()",
+      browser(), embedded_test_server()->GetURL("/test1"), "navigate2()",
       "empty.html");
 
   DelayLoadStartAndExecuteJavascript call_script_user_gesture(
-      embedded_test_server()->GetURL("/test2"),
-      "navigate2()",
+      browser(), embedded_test_server()->GetURL("/test2"), "navigate2()",
       "empty.html");
   call_script_user_gesture.set_has_user_gesture(true);
 
@@ -518,14 +512,12 @@
 
   // See crossProcessFragment/f.html.
   DelayLoadStartAndExecuteJavascript call_script3(
-      embedded_test_server()->GetURL("/test3"),
-      "updateFragment()",
+      browser(), embedded_test_server()->GetURL("/test3"), "updateFragment()",
       base::StringPrintf("f.html?%u#foo", embedded_test_server()->port()));
 
   // See crossProcessFragment/g.html.
   DelayLoadStartAndExecuteJavascript call_script4(
-      embedded_test_server()->GetURL("/test4"),
-      "updateFragment()",
+      browser(), embedded_test_server()->GetURL("/test4"), "updateFragment()",
       base::StringPrintf("g.html?%u#foo", embedded_test_server()->port()));
 
   ASSERT_TRUE(RunExtensionTest("webnavigation/crossProcessFragment"))
@@ -537,20 +529,17 @@
 
   // See crossProcessHistory/e.html.
   DelayLoadStartAndExecuteJavascript call_script2(
-      embedded_test_server()->GetURL("/test2"),
-      "updateHistory()",
+      browser(), embedded_test_server()->GetURL("/test2"), "updateHistory()",
       "empty.html");
 
   // See crossProcessHistory/h.html.
   DelayLoadStartAndExecuteJavascript call_script5(
-      embedded_test_server()->GetURL("/test5"),
-      "updateHistory()",
+      browser(), embedded_test_server()->GetURL("/test5"), "updateHistory()",
       "empty.html");
 
   // See crossProcessHistory/i.html.
   DelayLoadStartAndExecuteJavascript call_script6(
-      embedded_test_server()->GetURL("/test6"),
-      "updateHistory()",
+      browser(), embedded_test_server()->GetURL("/test6"), "updateHistory()",
       "empty.html");
 
   ASSERT_TRUE(RunExtensionTest("webnavigation/crossProcessHistory"))
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 848a6d9..eb78de66 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -443,7 +443,9 @@
   result->SetBoolean(tabs_constants::kFocusedKey, window->IsActive());
   const Profile* profile = browser.profile();
   result->SetBoolean(tabs_constants::kIncognitoKey, profile->IsOffTheRecord());
-  result->SetBoolean(tabs_constants::kAlwaysOnTopKey, window->IsAlwaysOnTop());
+  result->SetBoolean(
+      tabs_constants::kAlwaysOnTopKey,
+      window->GetZOrderLevel() == ui::ZOrderLevel::kFloatingWindow);
 
   std::string window_state;
   if (window->IsMinimized()) {
diff --git a/chrome/browser/favicon/OWNERS b/chrome/browser/favicon/OWNERS
index c888e87..77ebe9f 100644
--- a/chrome/browser/favicon/OWNERS
+++ b/chrome/browser/favicon/OWNERS
@@ -4,3 +4,4 @@
 
 # Temporary owner, for refactoring changes only.
 caitkp@chromium.org
+# COMPONENT: UI>Browser>History
diff --git a/chrome/browser/feedback/system_logs/about_system_logs_fetcher.cc b/chrome/browser/feedback/system_logs/about_system_logs_fetcher.cc
index 5cadd2e..c5d9aea 100644
--- a/chrome/browser/feedback/system_logs/about_system_logs_fetcher.cc
+++ b/chrome/browser/feedback/system_logs/about_system_logs_fetcher.cc
@@ -21,7 +21,8 @@
 
 SystemLogsFetcher* BuildAboutSystemLogsFetcher() {
   const bool scrub_data = false;
-  SystemLogsFetcher* fetcher = new SystemLogsFetcher(scrub_data);
+  // We aren't anonymizing, so we can pass null for the 1st party IDs.
+  SystemLogsFetcher* fetcher = new SystemLogsFetcher(scrub_data, nullptr);
 
   fetcher->AddSource(std::make_unique<ChromeInternalLogSource>());
   fetcher->AddSource(std::make_unique<MemoryDetailsLogSource>());
diff --git a/chrome/browser/feedback/system_logs/chrome_system_logs_fetcher.cc b/chrome/browser/feedback/system_logs/chrome_system_logs_fetcher.cc
index d00e945..6d2fcdd 100644
--- a/chrome/browser/feedback/system_logs/chrome_system_logs_fetcher.cc
+++ b/chrome/browser/feedback/system_logs/chrome_system_logs_fetcher.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h"
 #include "chrome/browser/feedback/system_logs/log_sources/crash_ids_source.h"
 #include "chrome/browser/feedback/system_logs/log_sources/memory_details_log_source.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "components/feedback/system_logs/system_logs_fetcher.h"
 
 #if defined(OS_CHROMEOS)
@@ -23,7 +24,8 @@
 
 SystemLogsFetcher* BuildChromeSystemLogsFetcher() {
   const bool scrub_data = true;
-  SystemLogsFetcher* fetcher = new SystemLogsFetcher(scrub_data);
+  SystemLogsFetcher* fetcher = new SystemLogsFetcher(
+      scrub_data, extension_misc::kBuiltInFirstPartyExtensionIds);
 
   fetcher->AddSource(std::make_unique<ChromeInternalLogSource>());
   fetcher->AddSource(std::make_unique<CrashIdsSource>());
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 5d395b1..c645382 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2953,11 +2953,6 @@
     "expiry_milestone": 80
   },
   {
-    "name": "sync-USS-autofill-wallet-metadata",
-    "owners": [ "jkrcal", "//components/sync/OWNERS" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "sync-support-secondary-account",
     "owners": [ "treib", "//components/sync/OWNERS" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 74266ecf..909c321 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1826,11 +1826,6 @@
     "a signed-in account that has not been chosen as Chrome's primary account. "
     "This only has an effect if sync-standalone-transport is also enabled.";
 
-const char kSyncUSSAutofillWalletMetadataName[] =
-    "Enable USS for autofill wallet metadata";
-const char kSyncUSSAutofillWalletMetadataDescription[] =
-    "Enables the new implementation of autofill walet metadata sync";
-
 const char kSyncSandboxName[] = "Use Chrome Sync sandbox";
 const char kSyncSandboxDescription[] =
     "Connects to the testing server for Chrome Sync.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index acf6e01..7393d1f0 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1088,9 +1088,6 @@
 extern const char kSyncSupportSecondaryAccountName[];
 extern const char kSyncSupportSecondaryAccountDescription[];
 
-extern const char kSyncUSSAutofillWalletMetadataName[];
-extern const char kSyncUSSAutofillWalletMetadataDescription[];
-
 extern const char kTabEngagementReportingName[];
 extern const char kTabEngagementReportingDescription[];
 
diff --git a/chrome/browser/history/OWNERS b/chrome/browser/history/OWNERS
index cdbd5d8..6f0ac8e 100644
--- a/chrome/browser/history/OWNERS
+++ b/chrome/browser/history/OWNERS
@@ -3,3 +3,4 @@
 per-file thumbnail_database.*=pkotwicz@chromium.org
 
 per-file download_database.*=benjhayden@chromium.org
+# COMPONENT: UI>Browser>History
diff --git a/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl.cc b/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl.cc
index 2377d7d..ec4b466 100644
--- a/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl.cc
+++ b/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl.cc
@@ -7,6 +7,7 @@
 #include <errno.h>
 #include <utility>
 
+#include "base/android/build_info.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
@@ -17,16 +18,16 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner_util.h"
 #include "chrome/android/chrome_jni_headers/OfflinePageArchivePublisherBridge_jni.h"
+#include "chrome/browser/offline_pages/android/offline_page_bridge.h"
 #include "components/offline_pages/core/archive_manager.h"
 #include "components/offline_pages/core/model/offline_page_model_utils.h"
 #include "components/offline_pages/core/offline_store_utils.h"
 
-using base::android::ScopedJavaLocalRef;
-
 namespace offline_pages {
 
 namespace {
 
+using base::android::ScopedJavaLocalRef;
 using offline_pages::SavePageResult;
 
 // Creates a singleton Delegate.
@@ -35,15 +36,25 @@
   return &delegate;
 }
 
+bool ShouldUseDownloadsCollection() {
+  return base::android::BuildInfo::GetInstance()->is_at_least_q();
+}
+
 // Helper function to do the move and register synchronously. Make sure this is
 // called from a background thread.
 PublishArchiveResult MoveAndRegisterArchive(
     const offline_pages::OfflinePageItem& offline_page,
     const base::FilePath& publish_directory,
     OfflinePageArchivePublisherImpl::Delegate* delegate) {
-  PublishArchiveResult archive_result;
+  // For Android Q+, use the downloads collection rather than DownloadManager.
+  if (ShouldUseDownloadsCollection()) {
+    return delegate->AddCompletedDownload(offline_page);
+  }
+
+  OfflinePageItem published_page(offline_page);
+
   // Calculate the new file name.
-  base::FilePath new_file_path =
+  published_page.file_path =
       offline_pages::model_utils::GenerateUniqueFilenameForOfflinePage(
           offline_page.title, offline_page.url, publish_directory);
 
@@ -54,9 +65,8 @@
   }
 
   // Move the file.
-  bool moved = base::Move(offline_page.file_path, new_file_path);
+  bool moved = base::Move(offline_page.file_path, published_page.file_path);
   if (!moved) {
-    archive_result.move_result = SavePageResult::FILE_MOVE_FAILED;
     DVPLOG(0) << "OfflinePage publishing file move failure " << __func__;
 
     if (!base::PathExists(offline_page.file_path)) {
@@ -67,38 +77,26 @@
       DVLOG(0) << "Target directory does not exist, " << publish_directory
                << " " << __func__;
     }
-    return archive_result;
+    return PublishArchiveResult::Failure(SavePageResult::FILE_MOVE_FAILED);
   }
 
   // Tell the download manager about our file, get back an id.
   if (!delegate->IsDownloadManagerInstalled()) {
-    archive_result.move_result = SavePageResult::ADD_TO_DOWNLOAD_MANAGER_FAILED;
-    return archive_result;
+    return PublishArchiveResult::Failure(
+        SavePageResult::ADD_TO_DOWNLOAD_MANAGER_FAILED);
   }
 
-  // TODO(petewil): Handle empty page title.
-  std::string page_title = base::UTF16ToUTF8(offline_page.title);
-  // We use the title for a description, since the add to the download manager
-  // fails without a description, and we don't have anything better to use.
-  int64_t download_id = delegate->AddCompletedDownload(
-      page_title, page_title,
-      offline_pages::store_utils::ToDatabaseFilePath(new_file_path),
-      offline_page.file_size, offline_page.url.spec(), std::string());
-  if (download_id == 0LL) {
-    archive_result.move_result = SavePageResult::ADD_TO_DOWNLOAD_MANAGER_FAILED;
-    return archive_result;
-  }
-
-  // Put results into the result object.
-  archive_result.move_result = SavePageResult::SUCCESS;
-  archive_result.new_file_path = new_file_path;
-  archive_result.download_id = download_id;
-
-  return archive_result;
+  return delegate->AddCompletedDownload(published_page);
 }
 
 }  // namespace
 
+// static
+PublishArchiveResult PublishArchiveResult::Failure(
+    SavePageResult save_page_result) {
+  return {save_page_result, PublishedArchiveId()};
+}
+
 OfflinePageArchivePublisherImpl::OfflinePageArchivePublisherImpl(
     ArchiveManager* archive_manager)
     : archive_manager_(archive_manager), delegate_(GetDefaultDelegate()) {}
@@ -122,7 +120,18 @@
 }
 
 void OfflinePageArchivePublisherImpl::UnpublishArchives(
-    const std::vector<int64_t>& download_manager_ids) const {
+    const std::vector<PublishedArchiveId>& publish_ids) const {
+  std::vector<int64_t> download_manager_ids;
+
+  for (auto& id : publish_ids) {
+    if (id.download_id == kArchivePublishedWithoutDownloadId) {
+      DCHECK(id.new_file_path.IsContentUri());
+      base::DeleteFile(id.new_file_path, false);
+    } else if (id.download_id != kArchiveNotPublished) {
+      download_manager_ids.push_back(id.download_id);
+    }
+  }
+
   delegate_->Remove(download_manager_ids);
 }
 
@@ -136,28 +145,51 @@
   return is_installed;
 }
 
-int64_t OfflinePageArchivePublisherImpl::Delegate::AddCompletedDownload(
-    const std::string& title,
-    const std::string& description,
-    const std::string& path,
-    int64_t length,
-    const std::string& uri,
-    const std::string& referer) {
+PublishArchiveResult
+OfflinePageArchivePublisherImpl::Delegate::AddCompletedDownload(
+    const OfflinePageItem& page) {
   JNIEnv* env = base::android::AttachCurrentThread();
+
+  if (ShouldUseDownloadsCollection()) {
+    base::FilePath new_file_path = base::FilePath(ConvertJavaStringToUTF8(
+        Java_OfflinePageArchivePublisherBridge_publishArchiveToDownloadsCollection(
+            env,
+            android::OfflinePageBridge::ConvertToJavaOfflinePage(env, page))));
+
+    if (new_file_path.empty())
+      return PublishArchiveResult::Failure(SavePageResult::FILE_MOVE_FAILED);
+
+    return {SavePageResult::SUCCESS,
+            {kArchivePublishedWithoutDownloadId, new_file_path}};
+  }
+
+  // TODO(petewil): Handle empty page title.
+  std::string page_title = base::UTF16ToUTF8(page.title);
+
   // Convert strings to jstring references.
   ScopedJavaLocalRef<jstring> j_title =
-      base::android::ConvertUTF8ToJavaString(env, title);
+      base::android::ConvertUTF8ToJavaString(env, page_title);
+  // We use the title for a description, since the add to the download manager
+  // fails without a description, and we don't have anything better to use.
   ScopedJavaLocalRef<jstring> j_description =
-      base::android::ConvertUTF8ToJavaString(env, description);
-  ScopedJavaLocalRef<jstring> j_path =
-      base::android::ConvertUTF8ToJavaString(env, path);
+      base::android::ConvertUTF8ToJavaString(env, page_title);
+  ScopedJavaLocalRef<jstring> j_path = base::android::ConvertUTF8ToJavaString(
+      env, offline_pages::store_utils::ToDatabaseFilePath(page.file_path));
   ScopedJavaLocalRef<jstring> j_uri =
-      base::android::ConvertUTF8ToJavaString(env, uri);
+      base::android::ConvertUTF8ToJavaString(env, page.url.spec());
   ScopedJavaLocalRef<jstring> j_referer =
-      base::android::ConvertUTF8ToJavaString(env, referer);
+      base::android::ConvertUTF8ToJavaString(env, std::string());
 
-  return Java_OfflinePageArchivePublisherBridge_addCompletedDownload(
-      env, j_title, j_description, j_path, length, j_uri, j_referer);
+  int64_t download_id =
+      Java_OfflinePageArchivePublisherBridge_addCompletedDownload(
+          env, j_title, j_description, j_path, page.file_size, j_uri,
+          j_referer);
+  DCHECK_NE(download_id, kArchivePublishedWithoutDownloadId);
+  if (download_id == kArchiveNotPublished)
+    return PublishArchiveResult::Failure(
+        SavePageResult::ADD_TO_DOWNLOAD_MANAGER_FAILED);
+
+  return {SavePageResult::SUCCESS, {download_id, page.file_path}};
 }
 
 int OfflinePageArchivePublisherImpl::Delegate::Remove(
diff --git a/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl.h b/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl.h
index 40fe4fe..0740e4f 100644
--- a/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl.h
+++ b/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl.h
@@ -31,18 +31,11 @@
     // Returns true if a system download manager is available on this platform.
     virtual bool IsDownloadManagerInstalled();
 
-    // Returns the download manager ID of the download, which we will place in
-    // the offline pages database as part of the offline page item.
-    // TODO(petewil): it might make sense to move all these params into a
-    // struct.
-    virtual int64_t AddCompletedDownload(const std::string& title,
-                                         const std::string& description,
-                                         const std::string& path,
-                                         int64_t length,
-                                         const std::string& uri,
-                                         const std::string& referer);
+    // Adds the archive to downloads.
+    virtual PublishArchiveResult AddCompletedDownload(
+        const OfflinePageItem& page);
 
-    // Returns the number of pages removed.
+    // Removes pages from downloads, returning the number of pages removed.
     virtual int Remove(
         const std::vector<int64_t>& android_download_manager_ids);
 
@@ -63,7 +56,7 @@
       PublishArchiveDoneCallback publish_done_callback) const override;
 
   void UnpublishArchives(
-      const std::vector<int64_t>& download_manager_ids) const override;
+      const std::vector<PublishedArchiveId>& publish_ids) const override;
 
  private:
   ArchiveManager* archive_manager_;
diff --git a/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl_unittest.cc b/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl_unittest.cc
index 66f829e..56089bc 100644
--- a/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl_unittest.cc
+++ b/chrome/browser/offline_pages/android/offline_page_archive_publisher_impl_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/offline_pages/android/offline_page_archive_publisher_impl.h"
 
+#include "base/android/build_info.h"
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -86,14 +87,11 @@
       : download_id_(id_to_use), last_removed_id_(0), installed_(installed) {}
 
   bool IsDownloadManagerInstalled() override { return installed_; }
-  int64_t AddCompletedDownload(const std::string& title,
-                               const std::string& description,
-                               const std::string& path,
-                               int64_t length,
-                               const std::string& uri,
-                               const std::string& referer) override {
-    return download_id_;
+  PublishArchiveResult AddCompletedDownload(
+      const OfflinePageItem& page) override {
+    return {SavePageResult::SUCCESS, {download_id_, page.file_path}};
   }
+
   int Remove(
       const std::vector<int64_t>& android_download_manager_ids) override {
     int count = static_cast<int>(android_download_manager_ids.size());
@@ -144,16 +142,26 @@
   PumpLoop();
 
   EXPECT_EQ(SavePageResult::SUCCESS, publish_archive_result().move_result);
-  EXPECT_EQ(kDownloadId, publish_archive_result().download_id);
-  // Check there is a file in the new location.
-  EXPECT_TRUE(public_archive_dir_path().IsParent(
-      publish_archive_result().new_file_path));
-  EXPECT_TRUE(base::PathExists(publish_archive_result().new_file_path));
-  // Check there is no longer a file in the old location.
-  EXPECT_FALSE(base::PathExists(old_file_path));
+  EXPECT_EQ(kDownloadId, publish_archive_result().id.download_id);
+
+  // The file move should not happen on Android Q and later.
+  if (!base::android::BuildInfo::GetInstance()->is_at_least_q()) {
+    // Check there is a file in the new location.
+    EXPECT_TRUE(public_archive_dir_path().IsParent(
+        publish_archive_result().id.new_file_path));
+    EXPECT_TRUE(base::PathExists(publish_archive_result().id.new_file_path));
+    // Check there is no longer a file in the old location.
+    EXPECT_FALSE(base::PathExists(old_file_path));
+  } else {
+    EXPECT_FALSE(public_archive_dir_path().IsParent(
+        publish_archive_result().id.new_file_path));
+    // new_file_path should be the same as the page's file path.
+    EXPECT_TRUE(base::PathExists(publish_archive_result().id.new_file_path));
+    EXPECT_TRUE(base::PathExists(old_file_path));
+  }
 }
 
-TEST_F(OfflinePageArchivePublisherImplTest, UnpublishArchive) {
+TEST_F(OfflinePageArchivePublisherImplTest, UnpublishArchives) {
   ArchiveManager archive_manager(temporary_dir_path(),
                                  private_archive_dir_path(),
                                  public_archive_dir_path(), task_runner());
@@ -162,7 +170,14 @@
   OfflinePageArchivePublisherImpl publisher(&archive_manager);
   publisher.SetDelegateForTesting(&delegate);
 
-  std::vector<int64_t> ids_to_remove = {kDownloadId};
+  // This needs to be very close to a real content URI or DeleteContentUri will
+  // throw an exception.
+  base::FilePath test_content_uri =
+      base::FilePath("content://downloads/download/43");
+
+  std::vector<PublishedArchiveId> ids_to_remove{
+      {kDownloadId, base::FilePath()},
+      {kArchivePublishedWithoutDownloadId, test_content_uri}};
   publisher.UnpublishArchives(std::move(ids_to_remove));
 
   EXPECT_EQ(kDownloadId, delegate.last_removed_id());
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index c5a7b46..b8ee315 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -1455,17 +1455,13 @@
               .get());
   ASSERT_TRUE(password_store->IsEmpty());
 
-  // Navigate to a page requiring HTTP auth. Wait for the tab to get the correct
-  // WebContents, but don't wait for navigation, which only finishes after
-  // authentication.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), http_test_server.GetURL("/basic_auth"),
-      WindowOpenDisposition::CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
-
   content::NavigationController* nav_controller =
       &WebContents()->GetController();
-  NavigationObserver nav_observer(WebContents());
   WindowedAuthNeededObserver auth_needed_observer(nav_controller);
+
+  // Navigate to a page requiring HTTP auth.
+  ui_test_utils::NavigateToURL(browser(),
+                               http_test_server.GetURL("/basic_auth"));
   auth_needed_observer.Wait();
 
   WindowedAuthSuppliedObserver auth_supplied_observer(nav_controller);
@@ -1473,6 +1469,7 @@
   ASSERT_EQ(1u, login_observer.handlers().size());
   LoginHandler* handler = *login_observer.handlers().begin();
   ASSERT_TRUE(handler);
+  NavigationObserver nav_observer(WebContents());
   // Any username/password will work.
   handler->SetAuth(base::UTF8ToUTF16("user"), base::UTF8ToUTF16("pwd"));
   auth_supplied_observer.Wait();
@@ -2953,9 +2950,8 @@
   content::NavigationController* nav_controller =
       &WebContents()->GetController();
   WindowedAuthNeededObserver auth_needed_observer(nav_controller);
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), http_test_server.GetURL("/basic_auth"),
-      WindowOpenDisposition::CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
+  ui_test_utils::NavigateToURL(browser(),
+                               http_test_server.GetURL("/basic_auth"));
   auth_needed_observer.Wait();
 
   // The auth dialog caused a query to PasswordStore, make sure it was
@@ -2984,9 +2980,7 @@
 
   content::NavigationController* controller = &WebContents()->GetController();
   WindowedAuthNeededObserver auth_needed_waiter(controller);
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), test_page, WindowOpenDisposition::CURRENT_TAB,
-      ui_test_utils::BROWSER_TEST_NONE);
+  ui_test_utils::NavigateToURL(browser(), test_page);
   auth_needed_waiter.Wait();
 
   BubbleObserver(WebContents()).WaitForManagementState();
@@ -3676,19 +3670,16 @@
     // should not work.
     ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
 
-    // Navigate to a page requiring HTTP auth. Wait for the tab to get the
-    // correct WebContents, but don't wait for navigation, which only finishes
-    // after authentication.
-    ui_test_utils::NavigateToURLWithDisposition(
-        browser(), http_test_server.GetURL("/basic_auth"),
-        WindowOpenDisposition::CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
-
     content::NavigationController* nav_controller =
         &WebContents()->GetController();
-    NavigationObserver nav_observer(WebContents());
     WindowedAuthNeededObserver auth_needed_observer(nav_controller);
+    // Navigate to a page requiring HTTP auth
+    ui_test_utils::NavigateToURL(browser(),
+                                 http_test_server.GetURL("/basic_auth"));
+
     auth_needed_observer.Wait();
 
+    NavigationObserver nav_observer(WebContents());
     WindowedAuthSuppliedObserver auth_supplied_observer(nav_controller);
     // Offer valid credentials on the auth challenge.
     ASSERT_EQ(1u, login_observer.handlers().size());
@@ -3752,19 +3743,15 @@
     std::string path("/basic_auth");
     if (is_realm_empty)
       path += "/empty_realm";
-    // Navigate to a page requiring HTTP auth. Wait for the tab to get the
-    // correct WebContents, but don't wait for navigation, which only finishes
-    // after authentication.
-    ui_test_utils::NavigateToURLWithDisposition(
-        browser(), http_test_server.GetURL(path),
-        WindowOpenDisposition::CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
 
     content::NavigationController* nav_controller =
         &WebContents()->GetController();
-    NavigationObserver nav_observer(WebContents());
     WindowedAuthNeededObserver auth_needed_observer(nav_controller);
+    // Navigate to a page requiring HTTP auth.
+    ui_test_utils::NavigateToURL(browser(), http_test_server.GetURL(path));
     auth_needed_observer.Wait();
 
+    NavigationObserver nav_observer(WebContents());
     WindowedAuthSuppliedObserver auth_supplied_observer(nav_controller);
 
     ASSERT_EQ(1u, login_observer.handlers().size());
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index e6c11a7..e90d0c4 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -683,9 +683,14 @@
 IN_PROC_BROWSER_TEST_F(PDFAnnotationsTest, MAYBE_AnnotationsFeatureEnabled) {
   RunTestsInFile("annotations_feature_enabled_test.js", "test.pdf");
 }
+
 IN_PROC_BROWSER_TEST_F(PDFExtensionTest, AnnotationsFeatureDisabled) {
   RunTestsInFile("annotations_feature_disabled_test.js", "test.pdf");
 }
+
+IN_PROC_BROWSER_TEST_F(PDFExtensionTest, Printing) {
+  RunTestsInFile("printing_icon_test.js", "test.pdf");
+}
 #endif
 
 // TODO(tsepez): See https://crbug.com/696650.
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 1b19c58..a7e8cbe 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -51,6 +51,7 @@
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/previews/previews_lite_page_decider.h"
 #include "chrome/browser/previews/previews_offline_helper.h"
+#include "chrome/browser/previews/previews_prober.h"
 #include "chrome/browser/profiles/chrome_version_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
@@ -730,6 +731,7 @@
   PrefsTabHelper::RegisterProfilePrefs(registry, locale);
   PreviewsLitePageDecider::RegisterProfilePrefs(registry);
   PreviewsOfflineHelper::RegisterProfilePrefs(registry);
+  PreviewsProber::RegisterProfilePrefs(registry);
   Profile::RegisterProfilePrefs(registry);
   ProfileImpl::RegisterProfilePrefs(registry);
   ProfileNetworkContextService::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/previews/previews_prober.cc b/chrome/browser/previews/previews_prober.cc
index c68ce58..62b7386 100644
--- a/chrome/browser/previews/previews_prober.cc
+++ b/chrome/browser/previews/previews_prober.cc
@@ -15,6 +15,9 @@
 #include "base/time/default_tick_clock.h"
 #include "build/build_config.h"
 #include "chrome/browser/previews/proto/previews_prober_cache_entry.pb.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/network_service_instance.h"
 #include "net/base/load_flags.h"
@@ -32,11 +35,19 @@
 
 namespace {
 
+const char kCachePrefKeyPrefix[] = "previews.prober.cache";
+
 std::string NameForClient(PreviewsProber::ClientName name) {
   switch (name) {
     case PreviewsProber::ClientName::kLitepages:
       return "litepages";
   }
+  NOTREACHED();
+  return std::string();
+}
+
+std::string PrefKeyForName(const std::string& name) {
+  return base::StringPrintf("%s.%s", kCachePrefKeyPrefix, name.c_str());
 }
 
 std::string HttpMethodToString(PreviewsProber::HttpMethod http_method) {
@@ -187,6 +198,7 @@
 PreviewsProber::PreviewsProber(
     Delegate* delegate,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    PrefService* pref_service,
     const ClientName name,
     const GURL& url,
     const HttpMethod http_method,
@@ -197,6 +209,7 @@
     base::TimeDelta revalidate_cache_after)
     : PreviewsProber(delegate,
                      url_loader_factory,
+                     pref_service,
                      name,
                      url,
                      http_method,
@@ -211,6 +224,7 @@
 PreviewsProber::PreviewsProber(
     Delegate* delegate,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    PrefService* pref_service,
     const ClientName name,
     const GURL& url,
     const HttpMethod http_method,
@@ -223,6 +237,7 @@
     const base::Clock* clock)
     : delegate_(delegate),
       name_(NameForClient(name)),
+      pref_key_(PrefKeyForName(NameForClient(name))),
       url_(url),
       http_method_(http_method),
       headers_(headers),
@@ -237,8 +252,11 @@
       clock_(clock),
       is_active_(false),
       network_connection_tracker_(nullptr),
-      url_loader_factory_(url_loader_factory) {
+      pref_service_(pref_service),
+      url_loader_factory_(url_loader_factory),
+      weak_factory_(this) {
   DCHECK(delegate_);
+  DCHECK(pref_service_);
 
   // The NetworkConnectionTracker can only be used directly on the UI thread.
   // Otherwise we use the cross-thread call.
@@ -250,6 +268,8 @@
         base::BindOnce(&PreviewsProber::AddSelfAsNetworkConnectionObserver,
                        weak_factory_.GetWeakPtr()));
   }
+  cached_probe_results_ =
+      pref_service_->GetDictionary(pref_key_)->CreateDeepCopy();
 }
 
 PreviewsProber::~PreviewsProber() {
@@ -258,6 +278,15 @@
     network_connection_tracker_->RemoveNetworkConnectionObserver(this);
 }
 
+// static
+void PreviewsProber::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  for (int i = 0; i <= static_cast<int>(PreviewsProber::ClientName::kMaxValue);
+       i++) {
+    registry->RegisterDictionaryPref(PrefKeyForName(
+        NameForClient(static_cast<PreviewsProber::ClientName>(i))));
+  }
+}
+
 void PreviewsProber::AddSelfAsNetworkConnectionObserver(
     network::NetworkConnectionTracker* network_connection_tracker) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -497,11 +526,13 @@
     return;
   }
 
-  cached_probe_results_->SetKey(GetCacheKeyForCurrentNetwork(),
-                                std::move(encoded.value()));
+  DictionaryPrefUpdate update(pref_service_, pref_key_);
+  update->SetKey(GetCacheKeyForCurrentNetwork(), std::move(encoded.value()));
 
-  if (cached_probe_results_->DictSize() > max_cache_entries_)
-    RemoveOldestDictionaryEntry(cached_probe_results_.get());
+  if (update.Get()->DictSize() > max_cache_entries_)
+    RemoveOldestDictionaryEntry(update.Get());
+
+  cached_probe_results_ = update.Get()->CreateDeepCopy();
 }
 
 std::string PreviewsProber::GetCacheKeyForCurrentNetwork() const {
diff --git a/chrome/browser/previews/previews_prober.h b/chrome/browser/previews/previews_prober.h
index 54e8812..46dd1ca 100644
--- a/chrome/browser/previews/previews_prober.h
+++ b/chrome/browser/previews/previews_prober.h
@@ -30,6 +30,9 @@
 #include "base/android/application_status_listener.h"
 #endif
 
+class PrefRegistrySimple;
+class PrefService;
+
 namespace network {
 class NetworkConnectionTracker;
 class SimpleURLLoader;
@@ -65,7 +68,9 @@
   // prefs.
   enum class ClientName {
     // TODO(crbug.com/971918): Use in litepages.
-    kLitepages,
+    kLitepages = 0,
+
+    kMaxValue = kLitepages,
   };
 
   // This enum describes the different algorithms that can be used to calculate
@@ -125,6 +130,7 @@
   PreviewsProber(
       Delegate* delegate,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      PrefService* pref_service,
       ClientName name,
       const GURL& url,
       HttpMethod http_method,
@@ -135,6 +141,9 @@
       base::TimeDelta revalidate_cache_after);
   ~PreviewsProber() override;
 
+  // Registers the prefs used in this class.
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
   // Sends a probe now if the prober is currently inactive. If the probe is
   // active (i.e.: there are probes in flight), this is a no-op. If
   // |send_only_in_foreground| is set, the probe will only be sent when the app
@@ -157,6 +166,7 @@
   PreviewsProber(
       Delegate* delegate,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      PrefService* pref_service,
       ClientName name,
       const GURL& url,
       HttpMethod http_method,
@@ -190,6 +200,9 @@
   // traffic annotations.
   const std::string name_;
 
+  // The pref key for used to recording |cached_probe_results_| to disk.
+  const std::string pref_key_;
+
   // The URL that will be probed.
   const GURL url_;
 
@@ -244,6 +257,9 @@
   // any thread.
   network::NetworkConnectionTracker* network_connection_tracker_;
 
+  // Reference for saving |cached_probe_results_| to prefs.
+  PrefService* pref_service_;
+
   // Used for setting up the |url_loader_|.
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
diff --git a/chrome/browser/previews/previews_prober_browsertest.cc b/chrome/browser/previews/previews_prober_browsertest.cc
index f51f5a13..1cb89de 100644
--- a/chrome/browser/previews/previews_prober_browsertest.cc
+++ b/chrome/browser/previews/previews_prober_browsertest.cc
@@ -129,6 +129,7 @@
   PreviewsProber::TimeoutPolicy timeout_policy;
 
   PreviewsProber prober(&delegate, browser()->profile()->GetURLLoaderFactory(),
+                        browser()->profile()->GetPrefs(),
                         PreviewsProber::ClientName::kLitepages, url,
                         PreviewsProber::HttpMethod::kGet, headers, retry_policy,
                         timeout_policy, 1, base::TimeDelta::FromDays(1));
@@ -150,6 +151,7 @@
   timeout_policy.base_timeout = base::TimeDelta::FromMilliseconds(1);
 
   PreviewsProber prober(&delegate, browser()->profile()->GetURLLoaderFactory(),
+                        browser()->profile()->GetPrefs(),
                         PreviewsProber::ClientName::kLitepages, url,
                         PreviewsProber::HttpMethod::kGet, headers, retry_policy,
                         timeout_policy, 1, base::TimeDelta::FromDays(1));
@@ -167,6 +169,7 @@
   PreviewsProber::TimeoutPolicy timeout_policy;
 
   PreviewsProber prober(&delegate, browser()->profile()->GetURLLoaderFactory(),
+                        browser()->profile()->GetPrefs(),
                         PreviewsProber::ClientName::kLitepages, url,
                         PreviewsProber::HttpMethod::kGet, headers, retry_policy,
                         timeout_policy, 1, base::TimeDelta::FromDays(1));
diff --git a/chrome/browser/previews/previews_prober_unittest.cc b/chrome/browser/previews/previews_prober_unittest.cc
index 9485abf..cdb2ea6 100644
--- a/chrome/browser/previews/previews_prober_unittest.cc
+++ b/chrome/browser/previews/previews_prober_unittest.cc
@@ -5,6 +5,9 @@
 #include "chrome/browser/previews/previews_prober.h"
 
 #include "build/build_config.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/testing_pref_service.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -49,6 +52,7 @@
   TestPreviewsProber(
       PreviewsProber::Delegate* delegate,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      PrefService* pref_service,
       const PreviewsProber::ClientName name,
       const GURL& url,
       const HttpMethod http_method,
@@ -61,6 +65,7 @@
       const base::Clock* clock)
       : PreviewsProber(delegate,
                        url_loader_factory,
+                       pref_service,
                        name,
                        url,
                        http_method,
@@ -81,7 +86,12 @@
         test_shared_loader_factory_(
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_)),
-        test_delegate_() {}
+        test_delegate_(),
+        test_prefs_() {}
+
+  void SetUp() override {
+    PreviewsProber::RegisterProfilePrefs(test_prefs_.registry());
+  }
 
   std::unique_ptr<PreviewsProber> NewProber() {
     return NewProberWithPolicies(PreviewsProber::RetryPolicy(),
@@ -107,7 +117,7 @@
     net::HttpRequestHeaders headers;
     headers.SetHeader("X-Testing", "Hello world");
     return std::make_unique<TestPreviewsProber>(
-        delegate, test_shared_loader_factory_,
+        delegate, test_shared_loader_factory_, &test_prefs_,
         PreviewsProber::ClientName::kLitepages, kTestUrl,
         PreviewsProber::HttpMethod::kGet, headers, retry_policy, timeout_policy,
         1, kCacheRevalidateAfter, thread_bundle_.GetMockTickClock(),
@@ -175,6 +185,7 @@
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
   TestDelegate test_delegate_;
+  TestingPrefServiceSimple test_prefs_;
 };
 
 TEST_F(PreviewsProberTest, OK) {
@@ -307,6 +318,29 @@
   EXPECT_TRUE(prober->is_active());
 }
 
+TEST_F(PreviewsProberTest, PersistentCache) {
+  std::unique_ptr<PreviewsProber> prober = NewProber();
+  EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
+
+  prober->SendNowIfInactive(false);
+  VerifyRequest();
+
+  MakeResponseAndWait(net::HTTP_OK, net::OK);
+  EXPECT_TRUE(prober->LastProbeWasSuccessful().value());
+  EXPECT_FALSE(prober->is_active());
+
+  // Create a new prober instance and verify the cached probe result is used.
+  prober = NewProber();
+  EXPECT_TRUE(prober->LastProbeWasSuccessful().value());
+  EXPECT_FALSE(prober->is_active());
+
+  // Fast forward past the cache revalidation and check that the revalidation
+  // time was also persisted.
+  FastForward(kCacheRevalidateAfter);
+  EXPECT_TRUE(prober->LastProbeWasSuccessful().value());
+  EXPECT_TRUE(prober->is_active());
+}
+
 #if defined(OS_ANDROID)
 TEST_F(PreviewsProberTest, StartInForeground) {
   std::unique_ptr<PreviewsProber> prober = NewProber();
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 6c61fc3..b771ba3 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -147,7 +147,6 @@
 #include "chrome/browser/extensions/browser_context_keyed_service_factories.h"
 #include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/ui/web_applications/web_app_metrics_factory.h"
-#include "chrome/browser/ui/web_applications/web_app_ui_service_factory.h"
 #include "chrome/browser/web_applications/web_app_provider_factory.h"
 #include "extensions/browser/api/networking_private/networking_private_delegate_factory.h"
 #include "extensions/browser/browser_context_keyed_service_factories.h"
@@ -405,7 +404,6 @@
 #endif
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   web_app::WebAppProviderFactory::GetInstance();
-  web_app::WebAppUiServiceFactory::GetInstance();
   web_app::WebAppMetricsFactory::GetInstance();
 #endif
   WebDataServiceFactory::GetInstance();
diff --git a/chrome/browser/profiles/gaia_info_update_service.cc b/chrome/browser/profiles/gaia_info_update_service.cc
index 7d35e26..7e36982 100644
--- a/chrome/browser/profiles/gaia_info_update_service.cc
+++ b/chrome/browser/profiles/gaia_info_update_service.cc
@@ -22,6 +22,7 @@
 #include "components/signin/public/base/signin_pref_names.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "content/public/browser/notification_details.h"
+#include "content/public/browser/storage_partition.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/image/image.h"
 
@@ -87,8 +88,14 @@
   return 256;
 }
 
-Profile* GAIAInfoUpdateService::GetBrowserProfile() {
-  return profile_;
+identity::IdentityManager* GAIAInfoUpdateService::GetIdentityManager() {
+  return IdentityManagerFactory::GetForProfile(profile_);
+}
+
+network::mojom::URLLoaderFactory* GAIAInfoUpdateService::GetURLLoaderFactory() {
+  return content::BrowserContext::GetDefaultStoragePartition(profile_)
+      ->GetURLLoaderFactoryForBrowserProcess()
+      .get();
 }
 
 std::string GAIAInfoUpdateService::GetCachedPictureURL() const {
diff --git a/chrome/browser/profiles/gaia_info_update_service.h b/chrome/browser/profiles/gaia_info_update_service.h
index 4ea91688..a6abf69 100644
--- a/chrome/browser/profiles/gaia_info_update_service.h
+++ b/chrome/browser/profiles/gaia_info_update_service.h
@@ -37,7 +37,8 @@
   // ProfileDownloaderDelegate:
   bool NeedsProfilePicture() const override;
   int GetDesiredImageSideLength() const override;
-  Profile* GetBrowserProfile() override;
+  identity::IdentityManager* GetIdentityManager() override;
+  network::mojom::URLLoaderFactory* GetURLLoaderFactory() override;
   std::string GetCachedPictureURL() const override;
   bool IsPreSignin() const override;
   void OnProfileDownloadSuccess(ProfileDownloader* downloader) override;
diff --git a/chrome/browser/profiles/profile_downloader.cc b/chrome/browser/profiles/profile_downloader.cc
index 7030449..408fab22 100644
--- a/chrome/browser/profiles/profile_downloader.cc
+++ b/chrome/browser/profiles/profile_downloader.cc
@@ -21,13 +21,10 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_downloader_delegate.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/signin/public/base/avatar_icon_util.h"
 #include "components/signin/public/identity_manager/access_token_fetcher.h"
 #include "components/signin/public/identity_manager/access_token_info.h"
 #include "components/signin/public/identity_manager/account_info.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
@@ -35,8 +32,6 @@
 #include "skia/ext/image_operations.h"
 #include "url/gurl.h"
 
-using content::BrowserThread;
-
 namespace {
 
 // Template for optional authorization header when using an OAuth access token.
@@ -47,8 +42,7 @@
 ProfileDownloader::ProfileDownloader(ProfileDownloaderDelegate* delegate)
     : delegate_(delegate),
       picture_status_(PICTURE_FAILED),
-      identity_manager_(IdentityManagerFactory::GetForProfile(
-          delegate_->GetBrowserProfile())),
+      identity_manager_(delegate_->GetIdentityManager()),
       identity_manager_observer_(this),
       waiting_for_account_info_(false) {
   DCHECK(delegate_);
@@ -60,8 +54,8 @@
 }
 
 void ProfileDownloader::StartForAccount(const std::string& account_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   VLOG(1) << "Starting profile downloader...";
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (!identity_manager_) {
     // This can happen in some test paths.
@@ -228,10 +222,7 @@
   }
 
   network::mojom::URLLoaderFactory* loader_factory =
-      content::BrowserContext::GetDefaultStoragePartition(
-          delegate_->GetBrowserProfile())
-          ->GetURLLoaderFactoryForBrowserProcess()
-          .get();
+      delegate_->GetURLLoaderFactory();
 
   simple_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
                                                     traffic_annotation);
@@ -242,7 +233,7 @@
 
 void ProfileDownloader::OnURLLoaderComplete(
     std::unique_ptr<std::string> response_body) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   int response_code = -1;
   if (simple_loader_->ResponseInfo() && simple_loader_->ResponseInfo()->headers)
     response_code = simple_loader_->ResponseInfo()->headers->response_code();
@@ -272,7 +263,7 @@
 }
 
 void ProfileDownloader::OnImageDecoded(const SkBitmap& decoded_image) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   int image_size = delegate_->GetDesiredImageSideLength();
   profile_picture_ = skia::ImageOperations::Resize(
       decoded_image,
@@ -284,7 +275,7 @@
 }
 
 void ProfileDownloader::OnDecodeImageFailed() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   delegate_->OnProfileDownloadFailure(
       this, ProfileDownloaderDelegate::IMAGE_DECODE_FAILED);
 }
diff --git a/chrome/browser/profiles/profile_downloader.h b/chrome/browser/profiles/profile_downloader.h
index 60d22b4..f75acd85 100644
--- a/chrome/browser/profiles/profile_downloader.h
+++ b/chrome/browser/profiles/profile_downloader.h
@@ -11,6 +11,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "base/sequence_checker.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/image_decoder.h"
 #include "components/signin/public/identity_manager/account_info.h"
@@ -112,6 +113,8 @@
   // can be downloaded.
   void StartFetchingOAuth2AccessToken();
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   ProfileDownloaderDelegate* delegate_;
   std::string account_id_;
   std::string auth_token_;
diff --git a/chrome/browser/profiles/profile_downloader_delegate.h b/chrome/browser/profiles/profile_downloader_delegate.h
index 3015112..a7aec77 100644
--- a/chrome/browser/profiles/profile_downloader_delegate.h
+++ b/chrome/browser/profiles/profile_downloader_delegate.h
@@ -9,9 +9,18 @@
 
 #include "base/strings/string16.h"
 
-class Profile;
 class ProfileDownloader;
 
+namespace identity {
+class IdentityManager;
+}  // namespace identity
+
+namespace network {
+namespace mojom {
+class URLLoaderFactory;
+}  // namespace mojom
+}  // namespace network
+
 // Reports on success or failure of Profile download. It is OK to delete the
 // |ProfileImageDownloader| instance in any of these handlers.
 class ProfileDownloaderDelegate {
@@ -39,8 +48,11 @@
   // cached URL.
   virtual std::string GetCachedPictureURL() const = 0;
 
-  // Returns the browser profile associated with this download request.
-  virtual Profile* GetBrowserProfile() = 0;
+  // Returns the IdentityManager associated with this download request.
+  virtual identity::IdentityManager* GetIdentityManager() = 0;
+
+  // Returns the URLLoaderFactory to use for this download request.
+  virtual network::mojom::URLLoaderFactory* GetURLLoaderFactory() = 0;
 
   // Returns true if the profile download is taking place before the user has
   // signed in. This can happen for example on Android and will trigger some
diff --git a/chrome/browser/profiles/profile_downloader_unittest.cc b/chrome/browser/profiles/profile_downloader_unittest.cc
index 6684cf1..437c11a 100644
--- a/chrome/browser/profiles/profile_downloader_unittest.cc
+++ b/chrome/browser/profiles/profile_downloader_unittest.cc
@@ -7,15 +7,18 @@
 #include "base/bind.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
 #include "chrome/browser/profiles/profile_downloader_delegate.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/browser/signin/test_signin_client_builder.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/signin/public/base/test_signin_client.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "net/url_request/test_url_fetcher_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -35,35 +38,22 @@
       public ProfileDownloaderDelegate,
       public identity::IdentityManager::DiagnosticsObserver {
  protected:
-  ProfileDownloaderTest()
-    : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
-  ~ProfileDownloaderTest() override {}
-
-  void SetUp() override {
-    TestingProfile::Builder builder;
-
-    profile_ = IdentityTestEnvironmentProfileAdaptor::
-        CreateProfileForIdentityTestEnvironment(builder);
-
-    profile_downloader_.reset(new ProfileDownloader(this));
-
-    identity_test_env_profile_adaptor_ =
-        std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_.get());
-    identity_test_env_ =
-        identity_test_env_profile_adaptor_->identity_test_env();
-    DCHECK(identity_test_env_);
-
-    identity_test_env_->identity_manager()->AddDiagnosticsObserver(this);
+  ProfileDownloaderTest() : profile_downloader_(this) {
+    identity_test_env_.identity_manager()->AddDiagnosticsObserver(this);
   }
-
-  void TearDown() override {
-    identity_test_env_->identity_manager()->RemoveDiagnosticsObserver(this);
+  ~ProfileDownloaderTest() override {
+    identity_test_env_.identity_manager()->RemoveDiagnosticsObserver(this);
   }
 
   bool NeedsProfilePicture() const override { return true; }
   int GetDesiredImageSideLength() const override { return 128; }
-  std::string GetCachedPictureURL() const override { return ""; }
-  Profile* GetBrowserProfile() override { return profile_.get(); }
+  std::string GetCachedPictureURL() const override { return std::string(); }
+  identity::IdentityManager* GetIdentityManager() override {
+    return identity_test_env_.identity_manager();
+  }
+  network::mojom::URLLoaderFactory* GetURLLoaderFactory() override {
+    return &test_url_loader_factory_;
+  }
   bool IsPreSignin() const override { return false; }
   void OnProfileDownloadSuccess(ProfileDownloader* downloader) override {
 
@@ -74,7 +64,7 @@
 
   void SimulateUserInfoSuccess(const std::string& picture_url,
                                const AccountInfo& account_info) {
-    identity_test_env_->SimulateSuccessfulFetchOfAccountInfo(
+    identity_test_env_.SimulateSuccessfulFetchOfAccountInfo(
         account_info.account_id, account_info.email, account_info.gaia,
         kTestHostedDomain, kTestFullName, kTestGivenName, kTestLocale,
         picture_url);
@@ -97,24 +87,23 @@
     on_access_token_request_callback_ = std::move(callback);
   }
 
-  content::TestBrowserThreadBundle thread_bundle_;
-  std::unique_ptr<Profile> profile_;
-  std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
-      identity_test_env_profile_adaptor_;
-  identity::IdentityTestEnvironment* identity_test_env_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  identity::IdentityTestEnvironment identity_test_env_;
+  ProfileDownloader profile_downloader_;
+
   base::OnceClosure on_access_token_request_callback_;
   std::string account_id_for_access_token_request_;
-  std::unique_ptr<ProfileDownloader> profile_downloader_;
 };
 
 TEST_F(ProfileDownloaderTest, FetchAccessToken) {
   AccountInfo account_info =
-      identity_test_env_->MakeAccountAvailable(kTestEmail);
-  identity_test_env_->SetRefreshTokenForAccount(account_info.account_id);
+      identity_test_env_.MakeAccountAvailable(kTestEmail);
+  identity_test_env_.SetRefreshTokenForAccount(account_info.account_id);
 
   base::RunLoop run_loop;
   set_on_access_token_requested_callback(run_loop.QuitClosure());
-  profile_downloader_->StartForAccount(account_info.account_id);
+  profile_downloader_.StartForAccount(account_info.account_id);
   run_loop.Run();
 
   EXPECT_EQ(account_info.account_id, account_id_for_access_token_request_);
@@ -122,63 +111,63 @@
 
 TEST_F(ProfileDownloaderTest, AccountInfoReady) {
   AccountInfo account_info =
-      identity_test_env_->MakeAccountAvailable(kTestEmail);
+      identity_test_env_.MakeAccountAvailable(kTestEmail);
   SimulateUserInfoSuccess(kTestValidPictureURL, account_info);
 
   ASSERT_EQ(ProfileDownloader::PICTURE_FAILED,
-            profile_downloader_->GetProfilePictureStatus());
+            profile_downloader_.GetProfilePictureStatus());
   base::RunLoop run_loop;
   set_on_access_token_requested_callback(run_loop.QuitClosure());
-  profile_downloader_->StartForAccount(account_info.account_id);
+  profile_downloader_.StartForAccount(account_info.account_id);
   run_loop.Run();
-  profile_downloader_->StartFetchingImage();
-  ASSERT_EQ(kTestValidPictureURL, profile_downloader_->GetProfilePictureURL());
+  profile_downloader_.StartFetchingImage();
+  ASSERT_EQ(kTestValidPictureURL, profile_downloader_.GetProfilePictureURL());
 }
 
 TEST_F(ProfileDownloaderTest, AccountInfoNotReady) {
   AccountInfo account_info =
-      identity_test_env_->MakeAccountAvailable(kTestEmail);
+      identity_test_env_.MakeAccountAvailable(kTestEmail);
   ASSERT_EQ(ProfileDownloader::PICTURE_FAILED,
-            profile_downloader_->GetProfilePictureStatus());
+            profile_downloader_.GetProfilePictureStatus());
   base::RunLoop run_loop;
   set_on_access_token_requested_callback(run_loop.QuitClosure());
-  profile_downloader_->StartForAccount(account_info.account_id);
+  profile_downloader_.StartForAccount(account_info.account_id);
   run_loop.Run();
-  profile_downloader_->StartFetchingImage();
+  profile_downloader_.StartFetchingImage();
   SimulateUserInfoSuccess(kTestValidPictureURL, account_info);
-  ASSERT_EQ(kTestValidPictureURL, profile_downloader_->GetProfilePictureURL());
+  ASSERT_EQ(kTestValidPictureURL, profile_downloader_.GetProfilePictureURL());
 }
 
 // Regression test for http://crbug.com/854907
 TEST_F(ProfileDownloaderTest, AccountInfoNoPictureDoesNotCrash) {
   AccountInfo account_info =
-      identity_test_env_->MakeAccountAvailable(kTestEmail);
+      identity_test_env_.MakeAccountAvailable(kTestEmail);
   SimulateUserInfoSuccess(kNoPictureURLFound, account_info);
 
   base::RunLoop run_loop;
   set_on_access_token_requested_callback(run_loop.QuitClosure());
-  profile_downloader_->StartForAccount(account_info.account_id);
+  profile_downloader_.StartForAccount(account_info.account_id);
   run_loop.Run();
-  profile_downloader_->StartFetchingImage();
+  profile_downloader_.StartFetchingImage();
 
-  EXPECT_TRUE(profile_downloader_->GetProfilePictureURL().empty());
+  EXPECT_TRUE(profile_downloader_.GetProfilePictureURL().empty());
   ASSERT_EQ(ProfileDownloader::PICTURE_DEFAULT,
-            profile_downloader_->GetProfilePictureStatus());
+            profile_downloader_.GetProfilePictureStatus());
 }
 
 // Regression test for http://crbug.com/854907
 TEST_F(ProfileDownloaderTest, AccountInfoInvalidPictureURLDoesNotCrash) {
   AccountInfo account_info =
-      identity_test_env_->MakeAccountAvailable(kTestEmail);
+      identity_test_env_.MakeAccountAvailable(kTestEmail);
   SimulateUserInfoSuccess(kTestInvalidPictureURL, account_info);
 
   base::RunLoop run_loop;
   set_on_access_token_requested_callback(run_loop.QuitClosure());
-  profile_downloader_->StartForAccount(account_info.account_id);
+  profile_downloader_.StartForAccount(account_info.account_id);
   run_loop.Run();
-  profile_downloader_->StartFetchingImage();
+  profile_downloader_.StartFetchingImage();
 
-  EXPECT_TRUE(profile_downloader_->GetProfilePictureURL().empty());
+  EXPECT_TRUE(profile_downloader_.GetProfilePictureURL().empty());
   ASSERT_EQ(ProfileDownloader::PICTURE_FAILED,
-            profile_downloader_->GetProfilePictureStatus());
+            profile_downloader_.GetProfilePictureStatus());
 }
diff --git a/chrome/browser/resources/downloads/manager.html b/chrome/browser/resources/downloads/manager.html
index acd701b..d736a5f 100644
--- a/chrome/browser/resources/downloads/manager.html
+++ b/chrome/browser/resources/downloads/manager.html
@@ -9,6 +9,7 @@
 <link rel="import" href="chrome://resources/cr_components/managed_footnote/managed_footnote.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast_manager.html">
 <link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/cr/ui.html">
@@ -20,7 +21,7 @@
 
 <dom-module id="downloads-manager">
   <template>
-    <style include="cr-hidden-style">
+    <style include="cr-shared-style cr-hidden-style">
       :host {
         display: flex;
         flex: 1 0;
@@ -42,10 +43,6 @@
         z-index: 1;
       }
 
-      #drop-shadow {
-        @apply --cr-container-shadow;
-      }
-
       :host([has-shadow_]) #drop-shadow {
         opacity: var(--cr-container-shadow-max-opacity);
       }
@@ -125,7 +122,7 @@
     <downloads-toolbar id="toolbar" spinner-active="{{spinnerActive_}}"
         role="none" on-search-changed="onSearchChanged_">
     </downloads-toolbar>
-    <div id="drop-shadow"></div>
+    <div id="drop-shadow" class="cr-container-shadow"></div>
     <div id="mainContainer" on-scroll="onScroll_">
       <managed-footnote hidden="[[inSearchMode_]]"></managed-footnote>
       <iron-list id="downloadsList" items="[[items_]]"
diff --git a/chrome/browser/resources/history/app.html b/chrome/browser/resources/history/app.html
index 736edaf..2e14bd0 100644
--- a/chrome/browser/resources/history/app.html
+++ b/chrome/browser/resources/history/app.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/cr/ui.html">
 <link rel="import" href="chrome://resources/html/cr/ui/command.html">
@@ -19,7 +20,7 @@
 
 <dom-module id="history-app">
   <template>
-    <style include="shared-style">
+    <style include="cr-shared-style shared-style">
       :host {
         color: var(--cr-primary-text-color);
         display: block;
@@ -48,10 +49,6 @@
         height: 100%;
       }
 
-      #drop-shadow {
-        @apply --cr-container-shadow;
-      }
-
       :host([toolbar-shadow_]) #drop-shadow {
         opacity: var(--cr-container-shadow-max-opacity);
       }
@@ -76,7 +73,7 @@
                                              queryState_.searchTerm)]]">
     </history-toolbar>
 
-    <div id="drop-shadow"></div>
+    <div id="drop-shadow" class="cr-container-shadow"></div>
     <div id="main-container">
       <history-side-bar id="content-side-bar" selected-page="{{selectedPage_}}"
           footer-info="[[footerInfo]]"
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js
index 00e4bc5..24c276f 100644
--- a/chrome/browser/resources/local_ntp/customize.js
+++ b/chrome/browser/resources/local_ntp/customize.js
@@ -1403,7 +1403,7 @@
   const menu = $(customize.IDS.MENU);
 
   $(customize.IDS.OPTIONS_TITLE).textContent =
-      configData.translatedStrings.customizeBackground;
+      configData.translatedStrings.customizeThisPage;
 
   if (configData.richerPicker) {
     // Store the main menu title so it can be restored if needed.
@@ -1411,12 +1411,12 @@
         $(customize.IDS.MENU_TITLE).textContent;
   }
 
-  $(customize.IDS.EDIT_BG_ICON)
+  $(customize.IDS.EDIT_BG)
       .setAttribute(
           'aria-label', configData.translatedStrings.customizeThisPage);
 
-  $(customize.IDS.EDIT_BG_ICON)
-      .setAttribute('title', configData.translatedStrings.customizeBackground);
+  $(customize.IDS.EDIT_BG)
+      .setAttribute('title', configData.translatedStrings.customizeThisPage);
 
   // Selecting a local image for the background should close the picker.
   if (configData.richerPicker) {
diff --git a/chrome/browser/resources/local_ntp/externs.js b/chrome/browser/resources/local_ntp/externs.js
index 92ed52f..4669cc4 100644
--- a/chrome/browser/resources/local_ntp/externs.js
+++ b/chrome/browser/resources/local_ntp/externs.js
@@ -373,7 +373,6 @@
 configData.translatedStrings.connectionError;
 configData.translatedStrings.connectionErrorNoPeriod;
 configData.translatedStrings.copyLink;
-configData.translatedStrings.customizeBackground;
 configData.translatedStrings.customizeButtonLabel;
 configData.translatedStrings.customizeThisPage;
 configData.translatedStrings.dailyRefresh;
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
index 2f87e5e..f6454c97 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
@@ -204,8 +204,8 @@
               title$="{{strings.tooltipDownload}}"></cr-icon-button>
 
           <cr-icon-button id="print" iron-icon="cr:print" on-click="print"
-              aria-label$="{{strings.tooltipPrint}}"
-              title$="{{strings.tooltipPrint}}"></cr-icon-button>
+              hidden="[[!printingEnabled]]" title$="{{strings.tooltipPrint}}"
+              aria-label$="{{strings.tooltipPrint}}"></cr-icon-button>
 
           <viewer-toolbar-dropdown id="bookmarks"
                                    selected
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
index 8e18564..006aa5c 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
@@ -80,6 +80,14 @@
       value: false,
     },
 
+    /**
+     * Whether the Printing feature is enabled.
+     */
+    printingEnabled: {
+      type: Boolean,
+      value: false,
+    },
+
     strings: Object,
   },
 
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js
index b62ace3..02763ae0 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.js
+++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -777,6 +777,7 @@
     $('toolbar').strings = strings;
     $('toolbar').pdfAnnotationsEnabled =
         loadTimeData.getBoolean('pdfAnnotationsEnabled');
+    $('toolbar').printingEnabled = loadTimeData.getBoolean('printingEnabled');
     $('zoom-toolbar').setStrings(strings);
     $('password-screen').strings = strings;
     $('error-screen').strings = strings;
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html
index a4acf13..98535e1 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -19,101 +19,96 @@
 <dom-module id="settings-a11y-page">
   <template>
     <style include="settings-shared"></style>
+    <template is="dom-if" if="[[showCaptionSettings_]]">
+      <cr-link-row class="hr" id="captions" label="$i18n{captionsTitle}"
+          on-click="onCaptionsClick_">
+      </cr-link-row>
+    </template>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
         section="a11y" focus-config="[[focusConfig_]]">
-      <if expr="not chromeos">
+<if expr="not chromeos">
+      <div route-path="default">
+      <settings-toggle-button
+          id="a11yImageLabels"
+          hidden$="[[!showAccessibilityLabelsSetting_]]"
+          pref="{{prefs.settings.a11y.enable_accessibility_image_labels}}"
+          on-change="onToggleAccessibilityImageLabels_"
+          label="$i18n{accessibleImageLabelsTitle}"
+          sub-label="$i18n{accessibleImageLabelsSubtitle}">
+      </settings-toggle-button>
+      <cr-link-row class="hr" label="$i18n{moreFeaturesLink}"
+          on-click="onMoreFeaturesLinkClick_" sub-label="$i18n{a11yWebStore}"
+          external>
+      </cr-link-row>
+      </div>
+</if>
+<if expr="chromeos or is_linux or is_win">
+      <template is="dom-if" if="[[showCaptionSettings_]]">
+        <template is="dom-if" route-path="/captions">
+          <settings-subpage
+              associated-control="[[$$('#captions')]]"
+              page-title="$i18n{captionsTitle}">
+            <settings-captions prefs="{{prefs}}"></settings-captions>
+          </settings-subpage>
+        </template>
+      </template>
+</if>
+<if expr="chromeos">
+      <template is="dom-if" if="[[pageVisibility.webstoreLink]]">
         <div route-path="default">
-          <template is="dom-if" if="[[showCaptionSettings_]]">
-            <cr-link-row class="hr" id="captions" label="$i18n{captionsTitle}"
-                on-click="onTapCaptions_">
-            </cr-link-row>
-          </template>
-          <if expr="not chromeos">
-            <settings-toggle-button id="a11yImageLabels"
-                hidden$="[[!showAccessibilityLabelsSetting_]]"
-                pref="{{prefs.settings.a11y.enable_accessibility_image_labels}}"
-                on-change="onToggleAccessibilityImageLabels_" 
-                label="$i18n{accessibleImageLabelsTitle}"
-                sub-label="$i18n{accessibleImageLabelsSubtitle}">
-            </settings-toggle-button>
-            <cr-link-row class="hr" label="$i18n{moreFeaturesLink}"
-                on-click="onMoreFeaturesLinkClick_"
-                sub-label="$i18n{a11yWebStore}" external></cr-link-row>
-          </if>
+          <settings-toggle-button
+              id="a11yImageLabels"
+              hidden$="[[!showAccessibilityLabelsSetting_]]"
+              pref="{{prefs.settings.a11y.enable_accessibility_image_labels}}"
+              on-change="onToggleAccessibilityImageLabels_"
+              label="$i18n{accessibleImageLabelsTitle}"
+              sub-label="$i18n{accessibleImageLabelsSubtitle}">
+          </settings-toggle-button>
+          <settings-toggle-button id="optionsInMenuToggle"
+              label="$i18n{optionsInMenuLabel}"
+              pref="{{prefs.settings.a11y.enable_menu}}">
+          </settings-toggle-button>
+          <cr-link-row class="hr" id="subpage-trigger"
+              label="$i18n{manageAccessibilityFeatures}"
+              on-click="onManageAccessibilityFeaturesTap_"
+              sub-label="$i18n{moreFeaturesLinkDescription}">
+          </cr-link-row>
         </div>
-      </if>
-      <if expr="chromeos">
-        <template is="dom-if" if="[[pageVisibility.webstoreLink]]">
-          <div route-path="default">
-            <template is="dom-if" if="[[showCaptionSettings_]]">
-              <cr-link-row class="hr" id="captions"
-                  label="$i18n{captionsTitle}"
-                  on-click="onTapCaptions_">
-              </cr-link-row>
-            </template>
-            <settings-toggle-button id="a11yImageLabels"
-                hidden$="[[!showAccessibilityLabelsSetting_]]"
-                pref="{{prefs.settings.a11y.enable_accessibility_image_labels}}"
-                on-change="onToggleAccessibilityImageLabels_"
-                label="$i18n{accessibleImageLabelsTitle}"
-                sub-label="$i18n{accessibleImageLabelsSubtitle}">
-            </settings-toggle-button>
-            <settings-toggle-button id="optionsInMenuToggle"
-                label="$i18n{optionsInMenuLabel}"
-                pref="{{prefs.settings.a11y.enable_menu}}">
-            </settings-toggle-button>
-            <cr-link-row class="hr" id="subpage-trigger"
-                label="$i18n{manageAccessibilityFeatures}"
-                on-click="onManageAccessibilityFeaturesTap_"
-                sub-label="$i18n{moreFeaturesLinkDescription}">
-            </cr-link-row>
-          </div>
-          <template is="dom-if" route-path="/manageAccessibility">
+        <template is="dom-if" route-path="/manageAccessibility">
+          <settings-subpage
+              associated-control="[[$$('#subpage-trigger')]]"
+              page-title="$i18n{manageAccessibilityFeatures}">
+            <settings-manage-a11y-page prefs="{{prefs}}">
+            </settings-manage-a11y-page>
+          </settings-subpage>
+        </template>
+        <template is="dom-if" route-path="/manageAccessibility/tts">
+          <settings-subpage
+              associated-control="[[$$('#subpage-trigger')]]"
+              page-title="$i18n{manageTtsSettings}">
+            <settings-tts-subpage prefs="{{prefs}}">
+            </settings-tts-subpage>
+          </settings-subpage>
+        </template>
+        <template is="dom-if" if="[[showExperimentalSwitchAccess_]]">
+          <template is="dom-if"
+              route-path="/manageAccessibility/switchAccess">
             <settings-subpage associated-control="[[$$('#subpage-trigger')]]"
-                page-title="$i18n{manageAccessibilityFeatures}">
-              <settings-manage-a11y-page prefs="{{prefs}}">
-              </settings-manage-a11y-page>
-            </settings-subpage>
-          </template>
-          <template is="dom-if" route-path="/manageAccessibility/tts">
-            <settings-subpage
-                associated-control="[[$$('#subpage-trigger')]]"
-                page-title="$i18n{manageTtsSettings}">
-              <settings-tts-subpage prefs="{{prefs}}">
-              </settings-tts-subpage>
-            </settings-subpage>
-          </template>
-          <template is="dom-if" if="[[showExperimentalSwitchAccess_]]">
-            <template is="dom-if"
-                route-path="/manageAccessibility/switchAccess">
-              <settings-subpage associated-control="[[$$('#subpage-trigger')]]"
-                  page-title="$i18n{manageSwitchAccessSettings}">
-                <settings-switch-access-subpage prefs="{{prefs.settings.a11y}}">
-                </settings-switch-access-subpage>
-              </settings-subpage>
-            </template>
-          </template>
-        </template>
-        <cr-link-row class="hr"
-            label="$i18n{moreFeaturesLink}"
-            on-click="onMoreFeaturesLinkClick_"
-            sub-label="$i18n{a11yWebStore}"
-            hidden="[[pageVisibility.webstoreLink]]" external></cr-link-row>
-      </if>
-
-      <if expr="chromeos or is_linux or is_win">
-        <template is="dom-if" if="[[showCaptionSettings_]]">
-          <template is="dom-if" route-path="/captions">
-            <settings-subpage
-                associated-control="[[$$('#captions')]]"
-                page-title="$i18n{captionsTitle}">
-              <settings-captions prefs="{{prefs}}"></settings-captions>
+                page-title="$i18n{manageSwitchAccessSettings}">
+              <settings-switch-access-subpage prefs="{{prefs.settings.a11y}}">
+              </settings-switch-access-subpage>
             </settings-subpage>
           </template>
         </template>
-      </if>
+      </template>
+</if>
     </settings-animated-pages>
-
+<if expr="chromeos">
+    <cr-link-row class="hr" label="$i18n{moreFeaturesLink}"
+        on-click="onMoreFeaturesLinkClick_" sub-label="$i18n{a11yWebStore}"
+        hidden="[[pageVisibility.webstoreLink]]" external>
+    </cr-link-row>
+</if>
   </template>
   <script src="a11y_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.js b/chrome/browser/resources/settings/a11y_page/a11y_page.js
index e1cfc42..a32699f 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.js
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.js
@@ -137,7 +137,7 @@
   },
 
   /** @private */
-  onTapCaptions_: function() {
+  onCaptionsClick_: function() {
     // Open the system captions dialog for Mac.
     // <if expr="is_macosx">
     settings.CaptionsBrowserProxyImpl.getInstance().openSystemCaptionsDialog();
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index e8137e5..ff230b5 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -194,8 +194,6 @@
     // Custom Backgrounds
     AddString(translated_strings.get(), "customizeButtonLabel",
               IDS_NTP_CUSTOMIZE_BUTTON_LABEL);
-    AddString(translated_strings.get(), "customizeBackground",
-              IDS_NTP_CUSTOM_BG_CUSTOMIZE_BACKGROUND);
     AddString(translated_strings.get(), "defaultWallpapers",
               IDS_NTP_CUSTOM_BG_CHROME_WALLPAPERS);
     AddString(translated_strings.get(), "uploadImage",
diff --git a/chrome/browser/sessions/OWNERS b/chrome/browser/sessions/OWNERS
index aab6f95..5467058 100644
--- a/chrome/browser/sessions/OWNERS
+++ b/chrome/browser/sessions/OWNERS
@@ -7,3 +7,4 @@
 per-file session_restore_android*=felipeg@chromium.org
 
 per-file session_restore*chromeos*=xiyuan@chromium.org
+# COMPONENT: UI>Browser>Sessions
diff --git a/chrome/browser/sharing/ack_message_handler.cc b/chrome/browser/sharing/ack_message_handler.cc
index 93d460e..5f93d0f 100644
--- a/chrome/browser/sharing/ack_message_handler.cc
+++ b/chrome/browser/sharing/ack_message_handler.cc
@@ -4,11 +4,22 @@
 
 #include "chrome/browser/sharing/ack_message_handler.h"
 
+#include "chrome/browser/sharing/proto/sharing_message.pb.h"
+
 AckMessageHandler::AckMessageHandler() = default;
 
 AckMessageHandler::~AckMessageHandler() = default;
 
 void AckMessageHandler::OnMessage(
     const chrome_browser_sharing::SharingMessage& message) {
-  // TODO
+  for (AckMessageObserver& observer : observers_)
+    observer.OnAckReceived(message.ack_message().original_message_id());
+}
+
+void AckMessageHandler::AddObserver(AckMessageObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void AckMessageHandler::RemoveObserver(AckMessageObserver* observer) {
+  observers_.RemoveObserver(observer);
 }
diff --git a/chrome/browser/sharing/ack_message_handler.h b/chrome/browser/sharing/ack_message_handler.h
index 84f8633..8e00dad 100644
--- a/chrome/browser/sharing/ack_message_handler.h
+++ b/chrome/browser/sharing/ack_message_handler.h
@@ -5,19 +5,41 @@
 #ifndef CHROME_BROWSER_SHARING_ACK_MESSAGE_HANDLER_H_
 #define CHROME_BROWSER_SHARING_ACK_MESSAGE_HANDLER_H_
 
+#include <string>
+
 #include "base/macros.h"
+#include "base/observer_list.h"
 #include "chrome/browser/sharing/sharing_message_handler.h"
 
+// Class to managae ack message and notify observers.
 class AckMessageHandler : public SharingMessageHandler {
  public:
+  // Interface for objects observing ack message received events.
+  class AckMessageObserver : public base::CheckedObserver {
+   public:
+    // Called when an ack message is received, where the identifier of original
+    // message is |message_id|.
+    virtual void OnAckReceived(const std::string& message_id) = 0;
+  };
+
   AckMessageHandler();
   ~AckMessageHandler() override;
 
+  // Add an observer ack message received events. An observer should not be
+  // added more than once.
+  void AddObserver(AckMessageObserver* observer);
+
+  // Removes the given observer from ack message received events. Does nothing
+  // if this observer has not been added.
+  void RemoveObserver(AckMessageObserver* observer);
+
   // SharingMessageHandler implementation:
   void OnMessage(
       const chrome_browser_sharing::SharingMessage& message) override;
 
  private:
+  base::ObserverList<AckMessageObserver> observers_;
+
   DISALLOW_COPY_AND_ASSIGN(AckMessageHandler);
 };
 
diff --git a/chrome/browser/sharing/ack_message_handler_unittest.cc b/chrome/browser/sharing/ack_message_handler_unittest.cc
new file mode 100644
index 0000000..2681295
--- /dev/null
+++ b/chrome/browser/sharing/ack_message_handler_unittest.cc
@@ -0,0 +1,47 @@
+// Copyright 2019 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 "chrome/browser/sharing/ack_message_handler.h"
+
+#include "chrome/browser/sharing/proto/sharing_message.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using SharingMessage = chrome_browser_sharing::SharingMessage;
+using namespace testing;
+
+namespace {
+
+const char kTestMessageId[] = "test_message_id";
+
+class TestObserver : public AckMessageHandler::AckMessageObserver {
+ public:
+  void OnAckReceived(const std::string& message_id) override {
+    received_message_id_ = message_id;
+  }
+
+  const std::string& received_message_id() { return received_message_id_; }
+
+ private:
+  std::string received_message_id_;
+};
+
+class AckMessageHandlerTest : public Test {
+ protected:
+  AckMessageHandlerTest() { ack_message_handler_.AddObserver(&test_observer_); }
+
+  AckMessageHandler ack_message_handler_;
+  TestObserver test_observer_;
+};
+
+}  // namespace
+
+TEST_F(AckMessageHandlerTest, OnMessage) {
+  SharingMessage sharing_message;
+  sharing_message.mutable_ack_message()->set_original_message_id(
+      kTestMessageId);
+
+  ack_message_handler_.OnMessage(sharing_message);
+
+  EXPECT_EQ(kTestMessageId, test_observer_.received_message_id());
+}
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc
index 67c4499..91d3ab5 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
 #include "chrome/browser/sharing/click_to_call/click_to_call_constants.h"
 #include "chrome/browser/sharing/click_to_call/feature.h"
+#include "chrome/browser/sharing/sharing_metrics.h"
 #include "chrome/browser/sharing/sharing_service.h"
 #include "chrome/browser/sharing/sharing_service_factory.h"
 #include "chrome/grit/generated_resources.h"
@@ -59,6 +60,7 @@
   url_ = params.link_url;
   devices_ = sharing_service_->GetDeviceCandidates(
       static_cast<int>(SharingDeviceCapability::kTelephony));
+  LogClickToCallDevicesToShow(devices_.size());
   if (devices_.empty())
     return;
 
@@ -148,8 +150,7 @@
                      AsWeakPtr()));
 }
 
-void ClickToCallContextMenuObserver::OnMessageSent(
-    base::Optional<std::string> message_id) const {
+void ClickToCallContextMenuObserver::OnMessageSent(bool sucess) const {
   // TODO(himanshujaju) Add metrics.
 }
 
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.h b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.h
index 44d622a..8bf38c0 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.h
+++ b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.h
@@ -65,7 +65,7 @@
 
   void SendClickToCallMessage(int chosen_device_index);
 
-  void OnMessageSent(base::Optional<std::string> message_id) const;
+  void OnMessageSent(bool sucess) const;
 
   gfx::ImageSkia GetContextMenuIcon() const;
 
diff --git a/chrome/browser/sharing/sharing_device_registration.cc b/chrome/browser/sharing/sharing_device_registration.cc
index b524865..8bb3035 100644
--- a/chrome/browser/sharing/sharing_device_registration.cc
+++ b/chrome/browser/sharing/sharing_device_registration.cc
@@ -51,8 +51,8 @@
   auto registration = sharing_sync_preference_->GetFCMRegistration();
   if (registration && registration->authorized_entity == authorized_entity &&
       (base::Time::Now() - registration->timestamp < kRegistrationExpiration)) {
-    // Authorized entity hasn't changed nor has expired, return success.
-    std::move(callback).Run(Result::SUCCESS);
+    // Authorized entity hasn't changed nor has expired, skip to next step.
+    RetrieveEncrpytionInfo(std::move(callback), registration->fcm_token);
     return;
   }
 
@@ -72,11 +72,9 @@
     instance_id::InstanceID::Result result) {
   switch (result) {
     case instance_id::InstanceID::SUCCESS:
-      gcm_driver_->GetEncryptionInfo(
-          kSharingFCMAppID,
-          base::BindOnce(&SharingDeviceRegistration::OnEncryptionInfoReceived,
-                         weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-                         authorized_entity, fcm_registration_token));
+      sharing_sync_preference_->SetFCMRegistration(
+          {authorized_entity, fcm_registration_token, base::Time::Now()});
+      RetrieveEncrpytionInfo(std::move(callback), fcm_registration_token);
       break;
     case instance_id::InstanceID::NETWORK_ERROR:
     case instance_id::InstanceID::SERVER_ERROR:
@@ -91,9 +89,18 @@
   }
 }
 
+void SharingDeviceRegistration::RetrieveEncrpytionInfo(
+    RegistrationCallback callback,
+    const std::string& fcm_registration_token) {
+  gcm_driver_->GetEncryptionInfo(
+      kSharingFCMAppID,
+      base::BindOnce(&SharingDeviceRegistration::OnEncryptionInfoReceived,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                     fcm_registration_token));
+}
+
 void SharingDeviceRegistration::OnEncryptionInfoReceived(
     RegistrationCallback callback,
-    const std::string& authorized_entity,
     const std::string& fcm_registration_token,
     std::string p256dh,
     std::string auth_secret) {
@@ -109,8 +116,6 @@
       fcm_registration_token, std::move(p256dh), std::move(auth_secret),
       device_capabilities);
   sharing_sync_preference_->SetSyncDevice(local_device_info->guid(), device);
-  sharing_sync_preference_->SetFCMRegistration(
-      {authorized_entity, fcm_registration_token, base::Time::Now()});
   std::move(callback).Run(Result::SUCCESS);
 }
 
diff --git a/chrome/browser/sharing/sharing_device_registration.h b/chrome/browser/sharing/sharing_device_registration.h
index 0ad2557..2bec442 100644
--- a/chrome/browser/sharing/sharing_device_registration.h
+++ b/chrome/browser/sharing/sharing_device_registration.h
@@ -84,10 +84,13 @@
   void OnFCMTokenDeleted(RegistrationCallback callback,
                          instance_id::InstanceID::Result result);
 
+  // Retrieve encryption info from GCMDriver.
+  void RetrieveEncrpytionInfo(RegistrationCallback callback,
+                              const std::string& fcm_registration_token);
+
   // Callback function responsible for saving device registration information in
   // SharingSyncPreference.
   void OnEncryptionInfoReceived(RegistrationCallback callback,
-                                const std::string& authorization_entity,
                                 const std::string& fcm_registration_token,
                                 std::string p256dh,
                                 std::string auth_secret);
diff --git a/chrome/browser/sharing/sharing_device_registration_unittest.cc b/chrome/browser/sharing/sharing_device_registration_unittest.cc
index 5622d3d..acb7d0a4 100644
--- a/chrome/browser/sharing/sharing_device_registration_unittest.cc
+++ b/chrome/browser/sharing/sharing_device_registration_unittest.cc
@@ -35,7 +35,9 @@
 const char kFCMToken[] = "test_fcm_token";
 const char kFCMToken2[] = "test_fcm_token_2";
 const char kDevicep256dh[] = "test_p256_dh";
+const char kDevicep256dh2[] = "test_p256_dh_2";
 const char kDeviceAuthSecret[] = "test_auth_secret";
+const char kDeviceAuthSecret2[] = "test_auth_secret_2";
 
 class MockInstanceIDDriver : public InstanceIDDriver {
  public:
@@ -104,11 +106,19 @@
 
   void GetEncryptionInfo(const std::string& app_id,
                          GetEncryptionInfoCallback callback) override {
-    std::move(callback).Run(kDevicep256dh, kDeviceAuthSecret);
+    std::move(callback).Run(p256dh_, auth_secret_);
+  }
+
+  void SetEncryptionInfo(const std::string& p256dh,
+                         const std::string& auth_secret) {
+    p256dh_ = p256dh;
+    auth_secret_ = auth_secret;
   }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeEncryptionGCMDriver);
+  std::string p256dh_ = kDevicep256dh;
+  std::string auth_secret_ = kDeviceAuthSecret;
 };
 
 class SharingDeviceRegistrationTest : public testing::Test {
@@ -222,18 +232,34 @@
 }
 
 TEST_F(SharingDeviceRegistrationTest, RegisterDeviceTest_VapidKeysUnchanged) {
+  SetInstanceIDFCMToken(kFCMToken);
   SetInstanceIDFCMResult(InstanceID::Result::SUCCESS);
+  std::string guid =
+      fake_local_device_info_provider_.GetLocalDeviceInfo()->guid();
 
   RegisterDeviceSync();
 
   EXPECT_EQ(SharingDeviceRegistration::Result::SUCCESS, result_);
 
-  // Set instance ID result to error. InstanceID shouldn't be invoked.
-  SetInstanceIDFCMResult(InstanceID::Result::UNKNOWN_ERROR);
+  // Instance ID now returns a new token, however it shouldn't be invoked.
+  SetInstanceIDFCMToken(kFCMToken2);
+  // GCMDriver now returns new encryption info.
+  fake_encryption_gcm_driver_.SetEncryptionInfo(kDevicep256dh2,
+                                                kDeviceAuthSecret2);
+
   // Register device again without changing VAPID keys.
   RegisterDeviceSync();
 
   EXPECT_EQ(SharingDeviceRegistration::Result::SUCCESS, result_);
+
+  auto it = devices_.find(guid);
+  ASSERT_NE(devices_.end(), it);
+  SharingSyncPreference::Device device(std::move(it->second));
+  // Encryption info is updated with new value.
+  EXPECT_EQ(kDeviceAuthSecret2, device.auth_secret);
+  EXPECT_EQ(kDevicep256dh2, device.p256dh);
+  // FCM token is not updated.
+  EXPECT_EQ(kFCMToken, device.fcm_token);
 }
 
 TEST_F(SharingDeviceRegistrationTest, RegisterDeviceTest_Expired) {
diff --git a/chrome/browser/sharing/sharing_fcm_handler.cc b/chrome/browser/sharing/sharing_fcm_handler.cc
index 82b12df..4052063 100644
--- a/chrome/browser/sharing/sharing_fcm_handler.cc
+++ b/chrome/browser/sharing/sharing_fcm_handler.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/sharing/fcm_constants.h"
 #include "chrome/browser/sharing/sharing_fcm_sender.h"
 #include "chrome/browser/sharing/sharing_message_handler.h"
+#include "chrome/browser/sharing/sharing_metrics.h"
 #include "chrome/browser/sharing/sharing_service_factory.h"
 #include "components/gcm_driver/gcm_driver.h"
 
@@ -72,6 +73,8 @@
   DCHECK(sharing_message.payload_case() != SharingMessage::PAYLOAD_NOT_SET)
       << "No payload set in SharingMessage received";
 
+  LogSharingMessageReceived(sharing_message.payload_case());
+
   auto it = sharing_handlers_.find(sharing_message.payload_case());
   if (it == sharing_handlers_.end()) {
     LOG(ERROR) << "No handler found for payload : "
diff --git a/chrome/browser/sharing/sharing_fcm_handler.h b/chrome/browser/sharing/sharing_fcm_handler.h
index 3e2a7ac..42a80a2b 100644
--- a/chrome/browser/sharing/sharing_fcm_handler.h
+++ b/chrome/browser/sharing/sharing_fcm_handler.h
@@ -37,11 +37,13 @@
   virtual void StopListening();
 
   // Registers |handler| for handling |payload_case| SharingMessage.
-  void AddSharingHandler(const SharingMessage::PayloadCase& payload_case,
-                         SharingMessageHandler* handler);
+  virtual void AddSharingHandler(
+      const SharingMessage::PayloadCase& payload_case,
+      SharingMessageHandler* handler);
 
   // Removes SharingMessageHandler registered for |payload_case|.
-  void RemoveSharingHandler(const SharingMessage::PayloadCase& payload_case);
+  virtual void RemoveSharingHandler(
+      const SharingMessage::PayloadCase& payload_case);
 
   // GCMAppHandler overrides.
   void ShutdownHandler() override;
diff --git a/chrome/browser/sharing/sharing_metrics.cc b/chrome/browser/sharing/sharing_metrics.cc
new file mode 100644
index 0000000..8d1ee3a
--- /dev/null
+++ b/chrome/browser/sharing/sharing_metrics.cc
@@ -0,0 +1,51 @@
+// Copyright 2019 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 "chrome/browser/sharing/sharing_metrics.h"
+
+#include "base/metrics/histogram_functions.h"
+
+namespace {
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class SharingMessageType {
+  kUnknownMessage = 0,
+  kPingMessage = 1,
+  kAckMessage = 2,
+  kClickToCallMessage = 3,
+  kMaxValue = kClickToCallMessage,
+};
+
+SharingMessageType PayloadCaseToMessageType(
+    chrome_browser_sharing::SharingMessage::PayloadCase payload_case) {
+  switch (payload_case) {
+    case chrome_browser_sharing::SharingMessage::PAYLOAD_NOT_SET:
+      return SharingMessageType::kUnknownMessage;
+    case chrome_browser_sharing::SharingMessage::kPingMessage:
+      return SharingMessageType::kPingMessage;
+    case chrome_browser_sharing::SharingMessage::kAckMessage:
+      return SharingMessageType::kAckMessage;
+    case chrome_browser_sharing::SharingMessage::kClickToCallMessage:
+      return SharingMessageType::kClickToCallMessage;
+  }
+}
+
+}  // namespace
+
+void LogSharingMessageReceived(
+    chrome_browser_sharing::SharingMessage::PayloadCase payload_case) {
+  base::UmaHistogramEnumeration("Sharing.MessageReceivedType",
+                                PayloadCaseToMessageType(payload_case));
+}
+
+void LogClickToCallDevicesToShow(int count) {
+  base::UmaHistogramExactLinear("Sharing.ClickToCallDevicesToShow", count,
+                                /*value_max=*/20);
+}
+
+void LogClickToCallAppsToShow(int count) {
+  base::UmaHistogramExactLinear("Sharing.ClickToCallAppsToShow", count,
+                                /*value_max=*/20);
+}
diff --git a/chrome/browser/sharing/sharing_metrics.h b/chrome/browser/sharing/sharing_metrics.h
new file mode 100644
index 0000000..c1f1327
--- /dev/null
+++ b/chrome/browser/sharing/sharing_metrics.h
@@ -0,0 +1,23 @@
+// Copyright 2019 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.
+
+#ifndef CHROME_BROWSER_SHARING_SHARING_METRICS_H_
+#define CHROME_BROWSER_SHARING_SHARING_METRICS_H_
+
+#include "chrome/browser/sharing/proto/sharing_message.pb.h"
+
+// Logs the |payload_case| to UMA. This should be called when a SharingMessage
+// is received.
+void LogSharingMessageReceived(
+    chrome_browser_sharing::SharingMessage::PayloadCase payload_case);
+
+// Logs the number of available devices that are about to be shown in a UI for
+// picking a device to start a phone call on.
+void LogClickToCallDevicesToShow(int count);
+
+// Logs the number of available apps that are about to be shown in a UI for
+// picking an app to start a phone call with.
+void LogClickToCallAppsToShow(int count);
+
+#endif  // CHROME_BROWSER_SHARING_SHARING_METRICS_H_
diff --git a/chrome/browser/sharing/sharing_service.cc b/chrome/browser/sharing/sharing_service.cc
index 5e620b8..b17f47e2 100644
--- a/chrome/browser/sharing/sharing_service.cc
+++ b/chrome/browser/sharing/sharing_service.cc
@@ -31,6 +31,12 @@
 namespace {
 // TODO(knollr): Should this be configurable or shared between similar features?
 constexpr base::TimeDelta kDeviceExpiration = base::TimeDelta::FromDays(2);
+
+// Amount of time before a message is considered timeout if no ack is received.
+constexpr base::TimeDelta kSendMessageTimeout =
+    base::TimeDelta::FromSeconds(10);
+
+// Backoff policy for registration retry.
 constexpr net::BackoffEntry::Policy kRetryBackoffPolicy = {
     // Number of initial errors (in sequence) to ignore before applying
     // exponential back-off rules.
@@ -87,6 +93,7 @@
   fcm_handler_->AddSharingHandler(
       chrome_browser_sharing::SharingMessage::kAckMessage,
       &ack_message_handler_);
+  ack_message_handler_.AddObserver(this);
   fcm_handler_->AddSharingHandler(
       chrome_browser_sharing::SharingMessage::kPingMessage,
       &ping_message_handler_);
@@ -116,6 +123,8 @@
 }
 
 SharingService::~SharingService() {
+  ack_message_handler_.RemoveObserver(this);
+
   if (sync_service_ && sync_service_->HasObserver(this))
     sync_service_->RemoveObserver(this);
 }
@@ -180,8 +189,41 @@
     base::TimeDelta time_to_live,
     chrome_browser_sharing::SharingMessage message,
     SendMessageCallback callback) {
-  fcm_sender_->SendMessageToDevice(device_guid, time_to_live,
-                                   std::move(message), std::move(callback));
+  fcm_sender_->SendMessageToDevice(
+      device_guid, time_to_live, std::move(message),
+      base::BindOnce(&SharingService::OnMessageSent,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void SharingService::OnMessageSent(SendMessageCallback callback,
+                                   base::Optional<std::string> message_id) {
+  if (!message_id) {
+    std::move(callback).Run(false);
+    return;
+  }
+
+  send_message_callbacks_.emplace(*message_id, std::move(callback));
+
+  base::PostDelayedTaskWithTraits(
+      FROM_HERE, {base::TaskPriority::BEST_EFFORT, content::BrowserThread::UI},
+      base::BindOnce(&SharingService::InvokeSendMessageCallback,
+                     weak_ptr_factory_.GetWeakPtr(), *message_id, false),
+      kSendMessageTimeout);
+}
+
+void SharingService::OnAckReceived(const std::string& message_id) {
+  InvokeSendMessageCallback(message_id, /*success=*/true);
+}
+
+void SharingService::InvokeSendMessageCallback(const std::string& message_id,
+                                               bool result) {
+  auto iter = send_message_callbacks_.find(message_id);
+  if (iter == send_message_callbacks_.end())
+    return;
+
+  SendMessageCallback callback = std::move(iter->second);
+  send_message_callbacks_.erase(iter);
+  std::move(callback).Run(result);
 }
 
 void SharingService::RegisterHandler(
diff --git a/chrome/browser/sharing/sharing_service.h b/chrome/browser/sharing/sharing_service.h
index b51f288..c0f65ca 100644
--- a/chrome/browser/sharing/sharing_service.h
+++ b/chrome/browser/sharing/sharing_service.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_SHARING_SHARING_SERVICE_H_
 #define CHROME_BROWSER_SHARING_SHARING_SERVICE_H_
 
+#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -40,10 +41,11 @@
 
 // Class to manage lifecycle of sharing feature, and provide APIs to send
 // sharing messages to other devices.
-class SharingService : public KeyedService, syncer::SyncServiceObserver {
+class SharingService : public KeyedService,
+                       syncer::SyncServiceObserver,
+                       AckMessageHandler::AckMessageObserver {
  public:
-  using SendMessageCallback =
-      base::OnceCallback<void(base::Optional<std::string>)>;
+  using SendMessageCallback = base::OnceCallback<void(bool)>;
 
   enum class State {
     // Device is unregistered with FCM and Sharing is unavailable.
@@ -95,10 +97,16 @@
   void OnSyncShutdown(syncer::SyncService* sync) override;
   void OnStateChanged(syncer::SyncService* sync) override;
 
+  // AckMessageHandler::AckMessageObserver override.
+  void OnAckReceived(const std::string& message_id) override;
+
   void RegisterDevice();
   void UnregisterDevice();
   void OnDeviceRegistered(SharingDeviceRegistration::Result result);
   void OnDeviceUnregistered(SharingDeviceRegistration::Result result);
+  void OnMessageSent(SendMessageCallback callback,
+                     base::Optional<std::string> message_id);
+  void InvokeSendMessageCallback(const std::string& message_id, bool result);
 
   // Returns true if sync is active and sync preference is enabled.
   bool IsSyncEnabled() const;
@@ -115,6 +123,7 @@
   PingMessageHandler ping_message_handler_;
   net::BackoffEntry backoff_entry_;
   State state_;
+  std::map<std::string, SendMessageCallback> send_message_callbacks_;
 
 #if defined(OS_ANDROID)
   ClickToCallMessageHandler click_to_call_message_handler_;
diff --git a/chrome/browser/sharing/sharing_service_unittest.cc b/chrome/browser/sharing/sharing_service_unittest.cc
index 6ce5bb4..3937587 100644
--- a/chrome/browser/sharing/sharing_service_unittest.cc
+++ b/chrome/browser/sharing/sharing_service_unittest.cc
@@ -9,10 +9,12 @@
 
 #include "base/guid.h"
 #include "base/memory/ptr_util.h"
+#include "base/optional.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "chrome/browser/sharing/fake_local_device_info_provider.h"
 #include "chrome/browser/sharing/features.h"
+#include "chrome/browser/sharing/proto/sharing_message.pb.h"
 #include "chrome/browser/sharing/sharing_device_info.h"
 #include "chrome/browser/sharing/sharing_device_registration.h"
 #include "chrome/browser/sharing/sharing_fcm_handler.h"
@@ -41,22 +43,35 @@
 const char kAuthSecret[] = "auth_secret";
 const char kFcmToken[] = "fcm_token";
 const char kDeviceName[] = "other_name";
+const char kMessageId[] = "message_id";
 const int kTtlSeconds = 10;
 
-class MockGCMDriver : public gcm::FakeGCMDriver {
+class FakeGCMDriver : public gcm::FakeGCMDriver {
  public:
-  MockGCMDriver() {}
-  ~MockGCMDriver() override {}
+  FakeGCMDriver() {}
+  ~FakeGCMDriver() override {}
 
-  MOCK_METHOD8(SendWebPushMessage,
-               void(const std::string& app_id,
-                    const std::string& authorized_entity,
-                    const std::string& p256dh,
-                    const std::string& auth_secret,
-                    const std::string& fcm_token,
-                    crypto::ECPrivateKey* vapid_key,
-                    gcm::WebPushMessage message,
-                    gcm::GCMDriver::SendWebPushMessageCallback callback));
+  void SendWebPushMessage(
+      const std::string& app_id,
+      const std::string& authorized_entity,
+      const std::string& p256dh,
+      const std::string& auth_secret,
+      const std::string& fcm_token,
+      crypto::ECPrivateKey* vapid_key,
+      gcm::WebPushMessage message,
+      gcm::GCMDriver::SendWebPushMessageCallback callback) override {
+    p256dh_ = p256dh;
+    auth_secret_ = auth_secret;
+    fcm_token_ = fcm_token;
+    std::move(callback).Run(base::make_optional(kMessageId));
+  }
+
+  const std::string& p256dh() { return p256dh_; }
+  const std::string& auth_secret() { return auth_secret_; }
+  const std::string& fcm_token() { return fcm_token_; }
+
+ private:
+  std::string p256dh_, auth_secret_, fcm_token_;
 };
 
 class MockInstanceIDDriver : public InstanceIDDriver {
@@ -69,12 +84,33 @@
 };
 
 class MockSharingFCMHandler : public SharingFCMHandler {
+  using SharingMessage = chrome_browser_sharing::SharingMessage;
+
  public:
   MockSharingFCMHandler() : SharingFCMHandler(nullptr, nullptr) {}
   ~MockSharingFCMHandler() = default;
 
   MOCK_METHOD0(StartListening, void());
   MOCK_METHOD0(StopListening, void());
+
+  void AddSharingHandler(const SharingMessage::PayloadCase& payload_case,
+                         SharingMessageHandler* handler) override {
+    sharing_handlers_[payload_case] = handler;
+  }
+
+  void RemoveSharingHandler(
+      const SharingMessage::PayloadCase& payload_case) override {
+    sharing_handlers_.erase(payload_case);
+  }
+
+  SharingMessageHandler* GetSharingHandler(
+      const SharingMessage::PayloadCase& payload_case) {
+    return sharing_handlers_[payload_case];
+  }
+
+ private:
+  std::map<SharingMessage::PayloadCase, SharingMessageHandler*>
+      sharing_handlers_;
 };
 
 class FakeSharingDeviceRegistration : public SharingDeviceRegistration {
@@ -122,16 +158,20 @@
     sync_prefs_ = new SharingSyncPreference(&prefs_);
     sharing_device_registration_ = new FakeSharingDeviceRegistration(
         sync_prefs_, &mock_instance_id_driver_, vapid_key_manager_,
-        &mock_gcm_driver_, &fake_local_device_info_provider_);
+        &fake_gcm_driver_, &fake_local_device_info_provider_);
     vapid_key_manager_ = new VapidKeyManager(sync_prefs_);
-    fcm_sender_ = new SharingFCMSender(&mock_gcm_driver_,
+    fcm_sender_ = new SharingFCMSender(&fake_gcm_driver_,
                                        &fake_local_device_info_provider_,
                                        sync_prefs_, vapid_key_manager_);
     fcm_handler_ = new NiceMock<MockSharingFCMHandler>();
     SharingSyncPreference::RegisterProfilePrefs(prefs_.registry());
   }
 
-  void OnMessageSent(base::Optional<std::string> message_id) {}
+  void OnMessageSent(bool success) {
+    send_message_success_ = base::make_optional(success);
+  }
+
+  base::Optional<bool> send_message_success() { return send_message_success_; }
 
  protected:
   static std::unique_ptr<syncer::DeviceInfo> CreateFakeDeviceInfo(
@@ -170,9 +210,9 @@
   FakeLocalDeviceInfoProvider fake_local_device_info_provider_;
   syncer::TestSyncService test_sync_service_;
   sync_preferences::TestingPrefServiceSyncable prefs_;
+  FakeGCMDriver fake_gcm_driver_;
 
   NiceMock<MockInstanceIDDriver> mock_instance_id_driver_;
-  NiceMock<MockGCMDriver> mock_gcm_driver_;
   NiceMock<MockSharingFCMHandler>* fcm_handler_;
 
   SharingSyncPreference* sync_prefs_;
@@ -182,6 +222,7 @@
 
  private:
   std::unique_ptr<SharingService> sharing_service_ = nullptr;
+  base::Optional<bool> send_message_success_;
 };
 
 }  // namespace
@@ -288,22 +329,70 @@
   EXPECT_EQ(id2, candidates[0].guid());
 }
 
-TEST_F(SharingServiceTest, SendMessageToDevice) {
+TEST_F(SharingServiceTest, SendMessageToDeviceSuccess) {
   std::string id = base::GenerateGUID();
   std::unique_ptr<syncer::DeviceInfo> device_info =
       CreateFakeDeviceInfo(id, kDeviceName);
   device_info_tracker_.Add(device_info.get());
   sync_prefs_->SetSyncDevice(id, CreateFakeSyncDevice());
 
-  EXPECT_CALL(mock_gcm_driver_,
-              SendWebPushMessage(_, _, Eq(kP256dh), Eq(kAuthSecret),
-                                 Eq(kFcmToken), _, _, _))
-      .Times(1);
   GetSharingService()->SendMessageToDevice(
       id, base::TimeDelta::FromSeconds(kTtlSeconds),
       chrome_browser_sharing::SharingMessage(),
       base::BindOnce(&SharingServiceTest::OnMessageSent,
                      base::Unretained(this)));
+
+  EXPECT_EQ(kP256dh, fake_gcm_driver_.p256dh());
+  EXPECT_EQ(kAuthSecret, fake_gcm_driver_.auth_secret());
+  EXPECT_EQ(kFcmToken, fake_gcm_driver_.fcm_token());
+
+  // Simulate ack message received by AckMessageHandler.
+  SharingMessageHandler* ack_message_handler = fcm_handler_->GetSharingHandler(
+      chrome_browser_sharing::SharingMessage::kAckMessage);
+  EXPECT_TRUE(ack_message_handler);
+
+  chrome_browser_sharing::SharingMessage ack_message;
+  ack_message.mutable_ack_message()->set_original_message_id(kMessageId);
+  ack_message_handler->OnMessage(ack_message);
+
+  EXPECT_TRUE(send_message_success().has_value());
+  EXPECT_TRUE(*send_message_success());
+}
+
+TEST_F(SharingServiceTest, SendMessageToDeviceExpired) {
+  std::string id = base::GenerateGUID();
+  std::unique_ptr<syncer::DeviceInfo> device_info =
+      CreateFakeDeviceInfo(id, kDeviceName);
+  device_info_tracker_.Add(device_info.get());
+  sync_prefs_->SetSyncDevice(id, CreateFakeSyncDevice());
+
+  GetSharingService()->SendMessageToDevice(
+      id, base::TimeDelta::FromSeconds(kTtlSeconds),
+      chrome_browser_sharing::SharingMessage(),
+      base::BindOnce(&SharingServiceTest::OnMessageSent,
+                     base::Unretained(this)));
+
+  EXPECT_EQ(kP256dh, fake_gcm_driver_.p256dh());
+  EXPECT_EQ(kAuthSecret, fake_gcm_driver_.auth_secret());
+  EXPECT_EQ(kFcmToken, fake_gcm_driver_.fcm_token());
+
+  // Advance time so send message will expire.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+  EXPECT_TRUE(send_message_success().has_value());
+  EXPECT_FALSE(*send_message_success());
+
+  // Simulate ack message received by AckMessageHandler, which will be
+  // disregarded.
+  SharingMessageHandler* ack_message_handler = fcm_handler_->GetSharingHandler(
+      chrome_browser_sharing::SharingMessage::kAckMessage);
+  EXPECT_TRUE(ack_message_handler);
+
+  chrome_browser_sharing::SharingMessage ack_message;
+  ack_message.mutable_ack_message()->set_original_message_id(kMessageId);
+  ack_message_handler->OnMessage(ack_message);
+
+  EXPECT_TRUE(send_message_success().has_value());
+  EXPECT_FALSE(*send_message_success());
 }
 
 TEST_F(SharingServiceTest, DeviceRegistration) {
diff --git a/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client.cc b/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client.cc
new file mode 100644
index 0000000..16a7a43df
--- /dev/null
+++ b/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client.cc
@@ -0,0 +1,358 @@
+// Copyright 2019 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 "chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client.h"
+
+#include <utility>
+
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/optional.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/supervised_user/supervised_user_constants.h"
+#include "components/google/core/common/google_util.h"
+#include "components/signin/public/identity_manager/access_token_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "google_apis/google_api_keys.h"
+#include "net/base/escape.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/url_request/url_request_status.h"
+#include "services/identity/public/cpp/scope_set.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+namespace {
+
+enum class RequestMethod {
+  kClassifyUrl,
+  kListFamilyMembers,
+  kRequestRestrictedUrlAccess,
+};
+
+constexpr char kClassifyUrlDataContentType[] =
+    "application/x-www-form-urlencoded";
+
+// Constants for ClassifyURL.
+constexpr char kClassifyUrlRequestApiPath[] =
+    "https://kidsmanagement-pa.googleapis.com/kidsmanagement/v1/people/"
+    "me:classifyUrl";
+constexpr char kClassifyUrlKidPermissionScope[] =
+    "https://www.googleapis.com/auth/kid.permission";
+constexpr char kClassifyUrlOauthConsumerName[] = "kids_url_classifier";
+constexpr char kClassifyUrlDataFormat[] = "url=%s&region_code=%s";
+constexpr char kClassifyUrlAllowed[] = "allowed";
+constexpr char kClassifyUrlRestricted[] = "restricted";
+
+// TODO(crbug.com/980273): remove conversion methods when experiment flag is
+// fully flipped. More info on crbug.com/978130.
+
+// Converts the ClassifyUrlRequest proto to a serialized string in the
+// format that the Kids Management API receives.
+std::string GetClassifyURLRequestString(
+    kids_chrome_management::ClassifyUrlRequest* request_proto) {
+  std::string query =
+      net::EscapeQueryParamValue(request_proto->url(), true /* use_plus */);
+  return base::StringPrintf(kClassifyUrlDataFormat, query.c_str(),
+                            request_proto->region_code().c_str());
+}
+
+// Converts the serialized string returned by the Kids Management API to a
+// ClassifyUrlResponse proto object.
+std::unique_ptr<kids_chrome_management::ClassifyUrlResponse>
+GetClassifyURLResponseProto(const std::string& response) {
+  base::Optional<base::Value> optional_value = base::JSONReader::Read(response);
+  const base::DictionaryValue* dict = nullptr;
+
+  auto response_proto =
+      std::make_unique<kids_chrome_management::ClassifyUrlResponse>();
+
+  if (!optional_value || !optional_value.value().GetAsDictionary(&dict)) {
+    DLOG(WARNING)
+        << "GetClassifyURLResponseProto failed to parse response dictionary";
+    response_proto->set_display_classification(
+        kids_chrome_management::ClassifyUrlResponse::
+            UNKNOWN_DISPLAY_CLASSIFICATION);
+    return response_proto;
+  }
+
+  const base::Value* classification_value =
+      dict->FindKey("displayClassification");
+  if (!classification_value) {
+    DLOG(WARNING)
+        << "GetClassifyURLResponseProto failed to parse displayClassification";
+    response_proto->set_display_classification(
+        kids_chrome_management::ClassifyUrlResponse::
+            UNKNOWN_DISPLAY_CLASSIFICATION);
+    return response_proto;
+  }
+
+  const std::string classification_string = classification_value->GetString();
+  if (classification_string == kClassifyUrlAllowed) {
+    response_proto->set_display_classification(
+        kids_chrome_management::ClassifyUrlResponse::ALLOWED);
+  } else if (classification_string == kClassifyUrlRestricted) {
+    response_proto->set_display_classification(
+        kids_chrome_management::ClassifyUrlResponse::RESTRICTED);
+  } else {
+    DLOG(WARNING)
+        << "GetClassifyURLResponseProto expected a valid displayClassification";
+    response_proto->set_display_classification(
+        kids_chrome_management::ClassifyUrlResponse::
+            UNKNOWN_DISPLAY_CLASSIFICATION);
+  }
+
+  return response_proto;
+}
+
+}  // namespace
+
+struct KidsChromeManagementClient::KidsChromeManagementRequest {
+  KidsChromeManagementRequest(
+      std::unique_ptr<google::protobuf::MessageLite> request_proto,
+      KidsChromeManagementClient::KidsChromeManagementCallback callback,
+      std::unique_ptr<network::ResourceRequest> resource_request,
+      const net::NetworkTrafficAnnotationTag traffic_annotation,
+      const char* oauth_consumer_name,
+      const char* scope,
+      const RequestMethod method)
+      : request_proto(std::move(request_proto)),
+        callback(std::move(callback)),
+        resource_request(std::move(resource_request)),
+        traffic_annotation(traffic_annotation),
+        access_token_expired(false),
+        oauth_consumer_name(oauth_consumer_name),
+        scope(scope),
+        method(method) {}
+
+  KidsChromeManagementRequest(KidsChromeManagementRequest&&) = default;
+
+  ~KidsChromeManagementRequest() { DCHECK(!callback); }
+
+  std::unique_ptr<google::protobuf::MessageLite> request_proto;
+  KidsChromeManagementCallback callback;
+  std::unique_ptr<network::ResourceRequest> resource_request;
+  const net::NetworkTrafficAnnotationTag traffic_annotation;
+  std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher>
+      access_token_fetcher;
+  bool access_token_expired;
+  const char* oauth_consumer_name;
+  const char* scope;
+  const RequestMethod method;
+};
+
+KidsChromeManagementClient::KidsChromeManagementClient(Profile* profile) {
+  url_loader_factory_ =
+      content::BrowserContext::GetDefaultStoragePartition(profile)
+          ->GetURLLoaderFactoryForBrowserProcess();
+
+  identity_manager_ = IdentityManagerFactory::GetForProfile(profile);
+}
+
+KidsChromeManagementClient::~KidsChromeManagementClient() = default;
+
+void KidsChromeManagementClient::ClassifyURL(
+    std::unique_ptr<kids_chrome_management::ClassifyUrlRequest> request_proto,
+    KidsChromeManagementCallback callback) {
+  DVLOG(1) << "Checking URL:  " << request_proto->url();
+
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = GURL(kClassifyUrlRequestApiPath);
+  resource_request->method = "POST";
+  resource_request->load_flags =
+      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+
+  const net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation(
+          "kids_chrome_management_client_classify_url", R"(
+        semantics {
+          sender: "Supervised Users"
+          description:
+            "Checks whether a given URL (or set of URLs) is considered safe by "
+            "a Google Family Link web restrictions API."
+          trigger:
+            "If the parent enabled this feature for the child account, this is "
+            "sent for every navigation."
+          data:
+            "An OAuth2 access token identifying and authenticating the "
+            "Google account, and the URL to be checked."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+          cookies_allowed: NO
+          setting:
+            "This feature is only used in child accounts and cannot be "
+            "disabled by settings. Parent accounts can disable it in the "
+            "family dashboard."
+          policy_exception_justification:
+            "Enterprise admins don't have control over this feature "
+            "because it can't be enabled on enterprise environements."
+        })");
+
+  auto kids_chrome_request = std::make_unique<KidsChromeManagementRequest>(
+      std::move(request_proto), std::move(callback),
+      std::move(resource_request), traffic_annotation,
+      kClassifyUrlOauthConsumerName, kClassifyUrlKidPermissionScope,
+      RequestMethod::kClassifyUrl);
+
+  MakeHTTPRequest(std::move(kids_chrome_request));
+}
+
+void KidsChromeManagementClient::MakeHTTPRequest(
+    std::unique_ptr<KidsChromeManagementRequest> kids_chrome_request) {
+  requests_in_progress_.push_front(std::move(kids_chrome_request));
+
+  StartFetching(requests_in_progress_.begin());
+}
+
+// Helpful reading for the next 4 methods:
+// https://chromium.googlesource.com/chromium/src.git/+/master/docs/callback.md#partial-binding-of-parameters-currying
+
+void KidsChromeManagementClient::StartFetching(
+    KidsChromeRequestList::iterator it) {
+  KidsChromeManagementRequest* req = it->get();
+
+  identity::ScopeSet scopes{req->scope};
+
+  req->access_token_fetcher =
+      std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
+          req->oauth_consumer_name, identity_manager_, scopes,
+          base::BindOnce(
+              &KidsChromeManagementClient::OnAccessTokenFetchComplete,
+              base::Unretained(this), it),
+          identity::PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
+}
+
+void KidsChromeManagementClient::OnAccessTokenFetchComplete(
+    KidsChromeRequestList::iterator it,
+    GoogleServiceAuthError error,
+    identity::AccessTokenInfo token_info) {
+  if (error.state() != GoogleServiceAuthError::NONE) {
+    DLOG(WARNING) << "Token error: " << error.ToString();
+
+    std::unique_ptr<google::protobuf::MessageLite> response_proto = nullptr;
+    DispatchResult(it, std::move(response_proto),
+                   KidsChromeManagementClient::ErrorCode::kTokenError);
+    return;
+  }
+
+  KidsChromeManagementRequest* req = it->get();
+
+  req->resource_request->headers.SetHeader(
+      net::HttpRequestHeaders::kAuthorization,
+      base::StringPrintf(supervised_users::kAuthorizationHeaderFormat,
+                         token_info.token.c_str()));
+
+  std::string request_data;
+  // TODO(crbug.com/980273): remove this when experiment flag is fully flipped.
+  if (req->method == RequestMethod::kClassifyUrl) {
+    request_data = GetClassifyURLRequestString(
+        static_cast<kids_chrome_management::ClassifyUrlRequest*>(
+            req->request_proto.get()));
+  } else {
+    DVLOG(1) << "Could not detect the request proto's class.";
+    std::unique_ptr<google::protobuf::MessageLite> response_proto = nullptr;
+    DispatchResult(it, std::move(response_proto),
+                   KidsChromeManagementClient::ErrorCode::kServiceError);
+    return;
+  }
+
+  std::unique_ptr<network::SimpleURLLoader> simple_url_loader =
+      network::SimpleURLLoader::Create(std::move(req->resource_request),
+                                       req->traffic_annotation);
+
+  simple_url_loader->AttachStringForUpload(request_data,
+                                           kClassifyUrlDataContentType);
+
+  simple_url_loader->DownloadToString(
+      url_loader_factory_.get(),
+      base::BindOnce(&KidsChromeManagementClient::OnSimpleLoaderComplete,
+                     base::Unretained(this), it, std::move(simple_url_loader),
+                     token_info),
+      /*max_body_size*/ 128);
+}
+
+void KidsChromeManagementClient::OnSimpleLoaderComplete(
+    KidsChromeRequestList::iterator it,
+    std::unique_ptr<network::SimpleURLLoader> simple_url_loader,
+    identity::AccessTokenInfo token_info,
+    std::unique_ptr<std::string> response_body) {
+  int response_code = -1;
+
+  if (simple_url_loader->ResponseInfo() &&
+      simple_url_loader->ResponseInfo()->headers) {
+    response_code = simple_url_loader->ResponseInfo()->headers->response_code();
+
+    KidsChromeManagementRequest* req = it->get();
+    // Handle first HTTP_UNAUTHORIZED response by removing access token and
+    // restarting the request from the beginning (fetching access token).
+    if (response_code == net::HTTP_UNAUTHORIZED && !req->access_token_expired) {
+      DLOG(WARNING) << "Access token expired:\n" << token_info.token;
+      req->access_token_expired = true;
+      identity::ScopeSet scopes{req->scope};
+      identity_manager_->RemoveAccessTokenFromCache(
+          identity_manager_->GetPrimaryAccountId(), scopes, token_info.token);
+      StartFetching(it);
+      return;
+    }
+  }
+
+  std::unique_ptr<google::protobuf::MessageLite> response_proto = nullptr;
+
+  int net_error = simple_url_loader->NetError();
+
+  if (net_error != net::OK) {
+    DLOG(WARNING) << "Network error " << net_error;
+    DispatchResult(it, std::move(response_proto),
+                   KidsChromeManagementClient::ErrorCode::kNetworkError);
+    return;
+  }
+
+  if (response_code != net::HTTP_OK) {
+    DLOG(WARNING) << "Response: " << response_body.get();
+    DispatchResult(it, std::move(response_proto),
+                   KidsChromeManagementClient::ErrorCode::kHttpError);
+    return;
+  }
+
+  // |response_body| is nullptr only in case of failure.
+  if (!response_body) {
+    DLOG(WARNING) << "URL request failed! Letting through...";
+    DispatchResult(it, std::move(response_proto),
+                   KidsChromeManagementClient::ErrorCode::kNetworkError);
+    return;
+  }
+
+  if (it->get()->method == RequestMethod::kClassifyUrl) {
+    response_proto = GetClassifyURLResponseProto(*response_body);
+  } else {
+    DVLOG(1) << "Could not detect the request proto class.";
+    DispatchResult(it, std::move(response_proto),
+                   KidsChromeManagementClient::ErrorCode::kServiceError);
+    return;
+  }
+
+  DispatchResult(it, std::move(response_proto),
+                 KidsChromeManagementClient::ErrorCode::kSuccess);
+}
+
+void KidsChromeManagementClient::DispatchResult(
+    KidsChromeRequestList::iterator it,
+    std::unique_ptr<google::protobuf::MessageLite> response_proto,
+    ErrorCode error) {
+  std::move(it->get()->callback).Run(std::move(response_proto), error);
+
+  requests_in_progress_.erase(it);
+}
diff --git a/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client.h b/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client.h
new file mode 100644
index 0000000..10a5a1a
--- /dev/null
+++ b/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client.h
@@ -0,0 +1,114 @@
+// Copyright 2019 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.
+
+#ifndef CHROME_BROWSER_SUPERVISED_USER_KIDS_CHROME_MANAGEMENT_KIDS_CHROME_MANAGEMENT_CLIENT_H_
+#define CHROME_BROWSER_SUPERVISED_USER_KIDS_CHROME_MANAGEMENT_KIDS_CHROME_MANAGEMENT_CLIENT_H_
+
+#include <list>
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "chrome/browser/supervised_user/kids_chrome_management/kidschromemanagement_messages.pb.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "third_party/protobuf/src/google/protobuf/message_lite.h"
+
+namespace identity {
+struct AccessTokenInfo;
+class IdentityManager;
+}  // namespace identity
+
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
+}  // namespace network
+
+class GoogleServiceAuthError;
+class Profile;
+
+// Provides an interface between Family Link RPC clients (e.g.
+// KidsManagementURLChecker) and the Kids Chrome Management Service.
+// Communicates with the server and performs HTTP requests.
+class KidsChromeManagementClient : public KeyedService {
+ public:
+  enum class ErrorCode {
+    kSuccess = 0,
+    kTokenError,    // Failed to get OAuth2 token.
+    kNetworkError,  // Network failure.
+    kHttpError,     // HTTP error.
+    kServiceError,  // Service returned an error or malformed reply.
+  };
+
+  using KidsChromeManagementCallback = base::OnceCallback<void(
+      std::unique_ptr<google::protobuf::MessageLite> response_proto,
+      ErrorCode error_code)>;
+
+  explicit KidsChromeManagementClient(Profile* profile);
+
+  ~KidsChromeManagementClient() override;
+
+  // Each of the next three methods is the interface to an RPC client.
+  // They receive only what's necessary for a request:
+  //   - The request proto, specific to each RPC.
+  //   - The callback that will receive the response proto and error code.
+
+  // Interface to KidsManagementURLCheckerClient. Classifies a URL as safe
+  // or restricted for a supervised user.
+  void ClassifyURL(
+      std::unique_ptr<kids_chrome_management::ClassifyUrlRequest> request_proto,
+      KidsChromeManagementCallback callback);
+
+  // TODO(crbug.com/979618): implement ListFamilyMembers method.
+
+  // TODO(crbug.com/979619): implement RequestRestrictedURLAccess method.
+
+ private:
+  // Every request must be represented by an instance of this struct. It will be
+  // added to a request list and its iterator will be passed along to the
+  // callbacks with request-specific information.
+  struct KidsChromeManagementRequest;
+
+  // Using a list ensures that iterators won't be invalidated when other
+  // elements are added/erased.
+  using KidsChromeRequestList =
+      std::list<std::unique_ptr<KidsChromeManagementRequest>>;
+
+  // Starts the execution flow by adding the request struct iterator to the
+  // execution list.
+  void MakeHTTPRequest(
+      std::unique_ptr<KidsChromeManagementRequest> kids_chrome_request);
+
+  // Fetches the user's access token.
+  void StartFetching(KidsChromeRequestList::iterator it);
+
+  void OnAccessTokenFetchComplete(
+      KidsChromeRequestList::iterator kids_chrome_request,
+      GoogleServiceAuthError auth_error,
+      identity::AccessTokenInfo token_info);
+
+  void OnSimpleLoaderComplete(
+      KidsChromeRequestList::iterator kids_chrome_request,
+      std::unique_ptr<network::SimpleURLLoader> simple_url_loader,
+      identity::AccessTokenInfo token_info,
+      std::unique_ptr<std::string> response_body);
+
+  // Calls the callback provided by the existing RPC client with the response
+  // proto and/or error codes.
+  void DispatchResult(
+      KidsChromeRequestList::iterator kids_chrome_request,
+      std::unique_ptr<google::protobuf::MessageLite> response_proto,
+      ErrorCode error);
+
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  identity::IdentityManager* identity_manager_;
+
+  // List of requests in execution.
+  KidsChromeRequestList requests_in_progress_;
+
+  DISALLOW_COPY_AND_ASSIGN(KidsChromeManagementClient);
+};
+
+#endif  // CHROME_BROWSER_SUPERVISED_USER_KIDS_CHROME_MANAGEMENT_KIDS_CHROME_MANAGEMENT_CLIENT_H_
diff --git a/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client_factory.cc b/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client_factory.cc
new file mode 100644
index 0000000..f502b0e
--- /dev/null
+++ b/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client_factory.cc
@@ -0,0 +1,35 @@
+// Copyright 2019 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 "chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client_factory.h"
+
+#include "chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+// static
+KidsChromeManagementClient*
+KidsChromeManagementClientFactory::GetForBrowserContext(Profile* profile) {
+  return static_cast<KidsChromeManagementClient*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+KidsChromeManagementClientFactory*
+KidsChromeManagementClientFactory::GetInstance() {
+  static base::NoDestructor<KidsChromeManagementClientFactory> factory;
+  return factory.get();
+}
+
+KidsChromeManagementClientFactory::KidsChromeManagementClientFactory()
+    : BrowserContextKeyedServiceFactory(
+          "KidsChromeManagementClientFactory",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+KidsChromeManagementClientFactory::~KidsChromeManagementClientFactory() =
+    default;
+
+KeyedService* KidsChromeManagementClientFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new KidsChromeManagementClient(static_cast<Profile*>(context));
+}
diff --git a/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client_factory.h b/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client_factory.h
new file mode 100644
index 0000000..7d836db
--- /dev/null
+++ b/chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client_factory.h
@@ -0,0 +1,44 @@
+// Copyright 2019 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.
+
+#ifndef CHROME_BROWSER_SUPERVISED_USER_KIDS_CHROME_MANAGEMENT_KIDS_CHROME_MANAGEMENT_CLIENT_FACTORY_H_
+#define CHROME_BROWSER_SUPERVISED_USER_KIDS_CHROME_MANAGEMENT_KIDS_CHROME_MANAGEMENT_CLIENT_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/no_destructor.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}
+
+class KidsChromeManagementClient;
+
+// Singleton that owns all KidsChromeManagementClient instances and associates
+// them with Profiles. Listens for the Profile's destruction
+// notification and cleans up the associated KidsChromeManagementClient.
+class KidsChromeManagementClientFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static KidsChromeManagementClient* GetForBrowserContext(Profile* profile);
+
+  static KidsChromeManagementClientFactory* GetInstance();
+
+ private:
+  friend class base::NoDestructor<KidsChromeManagementClientFactory>;
+
+  KidsChromeManagementClientFactory();
+  ~KidsChromeManagementClientFactory() override;
+
+  // The context parameter is guaranteed to be a Profile* because this is what
+  // GetForBrowserContext receives. It's only declared as a BrowserContext*
+  // because this method is overriding another one from the parent class.
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(KidsChromeManagementClientFactory);
+};
+
+#endif  // CHROME_BROWSER_SUPERVISED_USER_KIDS_CHROME_MANAGEMENT_KIDS_CHROME_MANAGEMENT_CLIENT_FACTORY_H_
diff --git a/chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.cc b/chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.cc
index 2340cf4..f5efd3a 100644
--- a/chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.cc
+++ b/chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.cc
@@ -9,6 +9,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
+#include "content/public/browser/storage_partition.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 
 CustodianProfileDownloaderService::CustodianProfileDownloaderService(
@@ -58,9 +59,18 @@
   return std::string();
 }
 
-Profile* CustodianProfileDownloaderService::GetBrowserProfile() {
+identity::IdentityManager*
+CustodianProfileDownloaderService::GetIdentityManager() {
   DCHECK(custodian_profile_);
-  return custodian_profile_;
+  return IdentityManagerFactory::GetForProfile(custodian_profile_);
+}
+
+network::mojom::URLLoaderFactory*
+CustodianProfileDownloaderService::GetURLLoaderFactory() {
+  DCHECK(custodian_profile_);
+  return content::BrowserContext::GetDefaultStoragePartition(custodian_profile_)
+      ->GetURLLoaderFactoryForBrowserProcess()
+      .get();
 }
 
 bool CustodianProfileDownloaderService::IsPreSignin() const {
diff --git a/chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.h b/chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.h
index d257193..26f473e 100644
--- a/chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.h
+++ b/chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.h
@@ -10,6 +10,8 @@
 #include "chrome/browser/profiles/profile_downloader_delegate.h"
 #include "components/keyed_service/core/keyed_service.h"
 
+class Profile;
+
 class CustodianProfileDownloaderService : public KeyedService,
                                           public ProfileDownloaderDelegate {
  public:
@@ -34,7 +36,8 @@
   bool NeedsProfilePicture() const override;
   int GetDesiredImageSideLength() const override;
   std::string GetCachedPictureURL() const override;
-  Profile* GetBrowserProfile() override;
+  identity::IdentityManager* GetIdentityManager() override;
+  network::mojom::URLLoaderFactory* GetURLLoaderFactory() override;
   bool IsPreSignin() const override;
   void OnProfileDownloadSuccess(ProfileDownloader* downloader) override;
   void OnProfileDownloadFailure(
diff --git a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
index fc10f85..572ad32 100644
--- a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
@@ -189,7 +189,7 @@
 
 // Flaky on all platform. See crbug.com/971666
 IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest,
-                       DISABLED_AddDuplicateProfiles_OneIsVerified) {
+                       AddDuplicateProfiles_OneIsVerified) {
   ASSERT_TRUE(SetupClients());
   base::HistogramTester histograms;
 
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 2173f5d..7c534e9 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -599,6 +599,42 @@
     SetColor(id, color);
 }
 
+void BrowserThemePack::SetTint(int id, color_utils::HSL tint) {
+  DCHECK(tints_);
+
+  int first_available_index = -1;
+  for (size_t i = 0; i < kTintTableLength; ++i) {
+    if (tints_[i].id == id) {
+      tints_[i].hsl = tint;
+      return;
+    }
+    if (tints_[i].id == -1 && first_available_index == -1)
+      first_available_index = i;
+  }
+
+  DCHECK_NE(-1, first_available_index);
+  tints_[first_available_index].id = id;
+  tints_[first_available_index].hsl = tint;
+}
+
+void BrowserThemePack::SetDisplayProperty(int id, int value) {
+  DCHECK(display_properties_);
+
+  int first_available_index = -1;
+  for (size_t i = 0; i < kDisplayPropertiesSize; ++i) {
+    if (display_properties_[i].id == id) {
+      display_properties_[i].property = value;
+      return;
+    }
+    if (display_properties_[i].id == -1 && first_available_index == -1)
+      first_available_index = i;
+  }
+
+  DCHECK_NE(-1, first_available_index);
+  display_properties_[first_available_index].id = id;
+  display_properties_[first_available_index].property = value;
+}
+
 SkColor BrowserThemePack::ComputeImageColor(const gfx::Image& image,
                                             int height) {
   // Include all colors in the analysis.
@@ -760,6 +796,14 @@
 
   pack->SetColor(TP::COLOR_TOOLBAR, colors.active_tab_color);
   pack->SetColor(TP::COLOR_TAB_TEXT, colors.active_tab_text_color);
+
+  // Always use alternate logo (not colorful one) even for white/grey/black
+  // backgrounds.
+  pack->SetDisplayProperty(TP::NTP_LOGO_ALTERNATE, 1);
+
+  // Don't change frame color for inactive window.
+  pack->SetTint(TP::TINT_FRAME_INACTIVE, {-1, -1, -1});
+  pack->SetTint(TP::TINT_FRAME_INCOGNITO_INACTIVE, {-1, -1, -1});
 }
 
 BrowserThemePack::BrowserThemePack(ThemeType theme_type)
@@ -811,9 +855,7 @@
   if (tints_) {
     for (size_t i = 0; i < kTintTableLength; ++i) {
       if (tints_[i].id == id) {
-        hsl->h = tints_[i].h;
-        hsl->s = tints_[i].s;
-        hsl->l = tints_[i].l;
+        *hsl = tints_[i].hsl;
         return true;
       }
     }
@@ -1035,9 +1077,7 @@
   tints_ = new TintEntry[kTintTableLength];
   for (size_t i = 0; i < kTintTableLength; ++i) {
     tints_[i].id = -1;
-    tints_[i].h = -1;
-    tints_[i].s = -1;
-    tints_[i].l = -1;
+    tints_[i].hsl = {-1, -1, -1};
   }
 }
 
@@ -1103,9 +1143,7 @@
        it != temp_tints.end() && count < kTintTableLength;
        ++it, ++count) {
     tints_[count].id = it->first;
-    tints_[count].h = it->second.h;
-    tints_[count].s = it->second.s;
-    tints_[count].l = it->second.l;
+    tints_[count].hsl = it->second;
   }
 }
 
diff --git a/chrome/browser/themes/browser_theme_pack.h b/chrome/browser/themes/browser_theme_pack.h
index 4943e5e..1b5f528 100644
--- a/chrome/browser/themes/browser_theme_pack.h
+++ b/chrome/browser/themes/browser_theme_pack.h
@@ -118,7 +118,7 @@
   ~BrowserThemePack() override;
 
   // Modifies |colors_| to set the entry with identifier |id| to |color|.  Only
-  // valid to call after BuildColorsFromJSON(), which creates |colors_|.
+  // valid to call after InitColors(), which creates |colors_|.
   void SetColor(int id, SkColor color);
 
   // If |colors_| does not already contain an entry with identifier |id|,
@@ -127,6 +127,14 @@
   // Only valid to call after BuildColorsFromJSON(), which creates |colors_|.
   void SetColorIfUnspecified(int id, SkColor color);
 
+  // Sets the value for |id| in |tints_|. Only valid to call after InitTints(),
+  // which creates |tints_|.
+  void SetTint(int id, color_utils::HSL tint);
+
+  // Sets the value for |id| in |display_properties_|. Only valid to call after
+  // InitDisplayProperties(), which creates |display_properties_|.
+  void SetDisplayProperty(int id, int value);
+
   // Calculates the dominant color of the top |height| rows of |image|.
   SkColor ComputeImageColor(const gfx::Image& image, int height);
 
@@ -293,9 +301,7 @@
   // will point directly to mmapped data.
   struct TintEntry {
     int32_t id;
-    double h;
-    double s;
-    double l;
+    color_utils::HSL hsl;
   }* tints_ = nullptr;
 
   struct ColorPair {
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index 7a7bc7d..38b4436 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -1137,6 +1137,24 @@
     EXPECT_NE(frame_color, toolbar_color);
     EXPECT_GE(color_utils::GetContrastRatio(frame_color, toolbar_color),
               kAutogeneratedThemeActiveTabMinContrast);
+
+    int ntp_logo_alternate;
+    EXPECT_TRUE(
+        pack->GetDisplayProperty(TP::NTP_LOGO_ALTERNATE, &ntp_logo_alternate));
+    EXPECT_EQ(1, ntp_logo_alternate);
+
+    color_utils::HSL hsl;
+    EXPECT_TRUE(pack->GetTint(TP::TINT_FRAME_INACTIVE, &hsl));
+    EXPECT_EQ(-1, hsl.h);
+    EXPECT_EQ(-1, hsl.s);
+    EXPECT_EQ(-1, hsl.l);
+
+    color_utils::HSL incognito_hsl;
+    EXPECT_TRUE(
+        pack->GetTint(TP::TINT_FRAME_INCOGNITO_INACTIVE, &incognito_hsl));
+    EXPECT_EQ(-1, incognito_hsl.h);
+    EXPECT_EQ(-1, incognito_hsl.s);
+    EXPECT_EQ(-1, incognito_hsl.l);
   }
 }
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 6efb3ac..e1ce4ef 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1453,8 +1453,6 @@
       "ash/keyboard/chrome_keyboard_ui_factory.h",
       "ash/keyboard/chrome_keyboard_web_contents.cc",
       "ash/keyboard/chrome_keyboard_web_contents.h",
-      "ash/kiosk_next_shell_client.cc",
-      "ash/kiosk_next_shell_client.h",
       "ash/launcher/app_shortcut_launcher_item_controller.cc",
       "ash/launcher/app_shortcut_launcher_item_controller.h",
       "ash/launcher/app_window_launcher_controller.cc",
@@ -2974,6 +2972,8 @@
       "views/session_crashed_bubble_view.h",
       "views/sharing/click_to_call/click_to_call_dialog_view.cc",
       "views/sharing/click_to_call/click_to_call_dialog_view.h",
+      "views/sharing/click_to_call/click_to_call_icon_view.cc",
+      "views/sharing/click_to_call/click_to_call_icon_view.h",
       "views/simple_message_box_views.cc",
       "views/simple_message_box_views.h",
       "views/status_bubble_views.cc",
@@ -3690,10 +3690,8 @@
       "web_applications/web_app_metrics.h",
       "web_applications/web_app_metrics_factory.cc",
       "web_applications/web_app_metrics_factory.h",
-      "web_applications/web_app_ui_service.cc",
-      "web_applications/web_app_ui_service.h",
-      "web_applications/web_app_ui_service_factory.cc",
-      "web_applications/web_app_ui_service_factory.h",
+      "web_applications/web_app_ui_manager_impl.cc",
+      "web_applications/web_app_ui_manager_impl.h",
       "webui/extensions/extension_basic_info.cc",
       "webui/extensions/extension_basic_info.h",
       "webui/extensions/extension_icon_source.cc",
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index 45c2f08..c9a73db 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -31,7 +31,6 @@
 #include "chrome/browser/ui/ash/cast_config_controller_media_router.h"
 #include "chrome/browser/ui/ash/chrome_new_window_client.h"
 #include "chrome/browser/ui/ash/ime_controller_client.h"
-#include "chrome/browser/ui/ash/kiosk_next_shell_client.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/browser/ui/ash/media_client_impl.h"
@@ -202,11 +201,6 @@
 
   // Initialize TabScrubber after the Ash Shell has been initialized.
   TabScrubber::GetInstance();
-
-  if (base::FeatureList::IsEnabled(ash::features::kKioskNextShell)) {
-    kiosk_next_shell_client_ = std::make_unique<KioskNextShellClient>();
-    kiosk_next_shell_client_->Init();
-  }
 }
 
 void ChromeBrowserMainExtraPartsAsh::PostBrowserStart() {
@@ -242,7 +236,6 @@
   display_settings_handler_.reset();
   media_client_.reset();
   login_screen_client_.reset();
-  kiosk_next_shell_client_.reset();
 
   // Initialized in PreProfileInit:
   system_tray_client_.reset();
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
index dc07dfe..31b405b6 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
@@ -26,7 +26,6 @@
 class CastConfigControllerMediaRouter;
 class ChromeNewWindowClient;
 class ImeControllerClient;
-class KioskNextShellClient;
 class LoginScreenClient;
 class MediaClientImpl;
 class MobileDataNotifications;
@@ -101,7 +100,6 @@
 #endif
 
   // Initialized in PostProfileInit in all configs:
-  std::unique_ptr<KioskNextShellClient> kiosk_next_shell_client_;
   std::unique_ptr<LoginScreenClient> login_screen_client_;
   std::unique_ptr<MediaClientImpl> media_client_;
   std::unique_ptr<policy::DisplaySettingsHandler> display_settings_handler_;
diff --git a/chrome/browser/ui/ash/kiosk_next_shell_client.cc b/chrome/browser/ui/ash/kiosk_next_shell_client.cc
deleted file mode 100644
index b32d313..0000000
--- a/chrome/browser/ui/ash/kiosk_next_shell_client.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2018 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 "chrome/browser/ui/ash/kiosk_next_shell_client.h"
-
-#include "base/logging.h"
-
-namespace {
-
-KioskNextShellClient* g_kiosk_next_shell_client_instance = nullptr;
-
-}  // namespace
-
-KioskNextShellClient::KioskNextShellClient() {
-  DCHECK(!g_kiosk_next_shell_client_instance);
-  g_kiosk_next_shell_client_instance = this;
-}
-
-KioskNextShellClient::~KioskNextShellClient() {
-  DCHECK_EQ(this, g_kiosk_next_shell_client_instance);
-  g_kiosk_next_shell_client_instance = nullptr;
-  ash::KioskNextShellController::Get()->SetClientAndLaunchSession(nullptr);
-}
-
-void KioskNextShellClient::Init() {
-  ash::KioskNextShellController::Get()->SetClientAndLaunchSession(this);
-}
-
-// static
-KioskNextShellClient* KioskNextShellClient::Get() {
-  return g_kiosk_next_shell_client_instance;
-}
-
-void KioskNextShellClient::LaunchKioskNextShell(const AccountId& account_id) {
-  // TODO(https://crbug.com/977019): Finish cleaning up this class.
-}
diff --git a/chrome/browser/ui/ash/kiosk_next_shell_client.h b/chrome/browser/ui/ash/kiosk_next_shell_client.h
deleted file mode 100644
index 081fc87..0000000
--- a/chrome/browser/ui/ash/kiosk_next_shell_client.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef CHROME_BROWSER_UI_ASH_KIOSK_NEXT_SHELL_CLIENT_H_
-#define CHROME_BROWSER_UI_ASH_KIOSK_NEXT_SHELL_CLIENT_H_
-
-#include "ash/public/cpp/kiosk_next_shell.h"
-#include "base/macros.h"
-
-class KioskNextShellClient : public ash::KioskNextShellClient {
- public:
-  KioskNextShellClient();
-  ~KioskNextShellClient() override;
-
-  void Init();
-
-  // Returns the singleton KioskNextShellClient instance, if it exists.
-  static KioskNextShellClient* Get();
-
-  // ash::KioskNextShellClient:
-  void LaunchKioskNextShell(const AccountId& account_id) override;
-
-  bool has_launched() const { return has_launched_; }
-
- private:
-  // True once the KioskNextShell has been launched.
-  bool has_launched_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(KioskNextShellClient);
-};
-
-#endif  // CHROME_BROWSER_UI_ASH_KIOSK_NEXT_SHELL_CLIENT_H_
diff --git a/chrome/browser/ui/ash/launcher/app_window_base.cc b/chrome/browser/ui/ash/launcher/app_window_base.cc
index 51d70fe..2805a7c2 100644
--- a/chrome/browser/ui/ash/launcher/app_window_base.cc
+++ b/chrome/browser/ui/ash/launcher/app_window_base.cc
@@ -103,11 +103,11 @@
   NOTREACHED();
 }
 
-bool AppWindowBase::IsAlwaysOnTop() const {
+ui::ZOrderLevel AppWindowBase::GetZOrderLevel() const {
   NOTREACHED();
-  return false;
+  return ui::ZOrderLevel::kNormal;
 }
 
-void AppWindowBase::SetAlwaysOnTop(bool always_on_top) {
+void AppWindowBase::SetZOrderLevel(ui::ZOrderLevel level) {
   NOTREACHED();
 }
diff --git a/chrome/browser/ui/ash/launcher/app_window_base.h b/chrome/browser/ui/ash/launcher/app_window_base.h
index a01e8bb..27db089 100644
--- a/chrome/browser/ui/ash/launcher/app_window_base.h
+++ b/chrome/browser/ui/ash/launcher/app_window_base.h
@@ -58,8 +58,8 @@
   void Restore() override;
   void SetBounds(const gfx::Rect& bounds) override;
   void FlashFrame(bool flash) override;
-  bool IsAlwaysOnTop() const override;
-  void SetAlwaysOnTop(bool always_on_top) override;
+  ui::ZOrderLevel GetZOrderLevel() const override;
+  void SetZOrderLevel(ui::ZOrderLevel order) override;
 
  private:
   ash::ShelfID shelf_id_;
diff --git a/chrome/browser/ui/autofill/payments/autofill_ui_util.cc b/chrome/browser/ui/autofill/payments/autofill_ui_util.cc
index d339f5f..03c8143 100644
--- a/chrome/browser/ui/autofill/payments/autofill_ui_util.cc
+++ b/chrome/browser/ui/autofill/payments/autofill_ui_util.cc
@@ -54,6 +54,7 @@
             ->GetOmniboxPageActionIconContainer()
             ->UpdatePageActionIcon(icon_type);
         break;
+      case PageActionIconType::kClickToCall:
       case PageActionIconType::kFind:
       case PageActionIconType::kIntentPicker:
       case PageActionIconType::kNativeFileSystemAccess:
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
index ce6103d..30a4180 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
@@ -35,7 +35,6 @@
 #import "ui/base/test/scoped_fake_nswindow_focus.h"
 #include "ui/base/test/scoped_fake_nswindow_fullscreen.h"
 #import "ui/base/test/windowed_nsnotification_observer.h"
-#import "ui/gfx/mac/nswindow_frame_controls.h"
 
 using extensions::AppWindow;
 using extensions::PlatformAppBrowserTest;
@@ -46,6 +45,10 @@
 
 namespace {
 
+bool IsNSWindowFloating(NSWindow* window) {
+  return [window level] != NSNormalWindowLevel;
+}
+
 class NativeAppWindowCocoaBrowserTest : public PlatformAppBrowserTest {
  protected:
   NativeAppWindowCocoaBrowserTest() {}
@@ -239,7 +242,7 @@
             app_window->fullscreen_types_for_test());
   EXPECT_FALSE(window->IsFullscreen());
   EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask);
-  EXPECT_TRUE(gfx::IsNSWindowAlwaysOnTop(ns_window));
+  EXPECT_TRUE(IsNSWindowFloating(ns_window));
 
   [ns_window toggleFullScreen:nil];
   [waiter waitForEnterCount:1 exitCount:0];
@@ -247,7 +250,7 @@
               AppWindow::FULLSCREEN_TYPE_OS);
   EXPECT_TRUE(window->IsFullscreen());
   EXPECT_TRUE([ns_window styleMask] & NSFullScreenWindowMask);
-  EXPECT_FALSE(gfx::IsNSWindowAlwaysOnTop(ns_window));
+  EXPECT_FALSE(IsNSWindowFloating(ns_window));
 
   app_window->Restore();
   EXPECT_FALSE(window->IsFullscreenOrPending());
@@ -256,7 +259,7 @@
             app_window->fullscreen_types_for_test());
   EXPECT_FALSE(window->IsFullscreen());
   EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask);
-  EXPECT_TRUE(gfx::IsNSWindowAlwaysOnTop(ns_window));
+  EXPECT_TRUE(IsNSWindowFloating(ns_window));
 
   app_window->Fullscreen();
   EXPECT_TRUE(window->IsFullscreenOrPending());
@@ -265,7 +268,7 @@
               AppWindow::FULLSCREEN_TYPE_WINDOW_API);
   EXPECT_TRUE(window->IsFullscreen());
   EXPECT_TRUE([ns_window styleMask] & NSFullScreenWindowMask);
-  EXPECT_FALSE(gfx::IsNSWindowAlwaysOnTop(ns_window));
+  EXPECT_FALSE(IsNSWindowFloating(ns_window));
 
   [ns_window toggleFullScreen:nil];
   [waiter waitForEnterCount:2 exitCount:2];
@@ -273,7 +276,7 @@
             app_window->fullscreen_types_for_test());
   EXPECT_FALSE(window->IsFullscreen());
   EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask);
-  EXPECT_TRUE(gfx::IsNSWindowAlwaysOnTop(ns_window));
+  EXPECT_TRUE(IsNSWindowFloating(ns_window));
 }
 
 // Test Minimize, Restore combinations with their native equivalents.
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
index ac91e9f..70e1549 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -16,8 +16,9 @@
 #include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_manager.h"
-#include "chrome/browser/ui/web_applications/web_app_ui_service.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/components/web_app_ui_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
@@ -304,19 +305,19 @@
 }
 
 bool HostedAppBrowserController::CanUninstall() const {
-  auto* web_app_ui_service =
-      web_app::WebAppUiService::Get(browser()->profile());
-  DCHECK(web_app_ui_service);
-  return web_app_ui_service->dialog_manager().CanUninstallWebApp(extension_id_);
+  return web_app::WebAppProvider::Get(browser()->profile())
+      ->ui_manager()
+      .dialog_manager()
+      .CanUninstallWebApp(extension_id_);
 }
 
 void HostedAppBrowserController::Uninstall() {
-  auto* web_app_ui_service =
-      web_app::WebAppUiService::Get(browser()->profile());
-  DCHECK(web_app_ui_service);
-  web_app_ui_service->dialog_manager().UninstallWebApp(
-      extension_id_, web_app::WebAppDialogManager::UninstallSource::kAppMenu,
-      browser()->window(), base::DoNothing());
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->ui_manager()
+      .dialog_manager()
+      .UninstallWebApp(extension_id_,
+                       web_app::WebAppDialogManager::UninstallSource::kAppMenu,
+                       browser()->window(), base::DoNothing());
 }
 
 bool HostedAppBrowserController::IsInstalled() const {
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc
index 724eec8..547c776 100644
--- a/chrome/browser/ui/hats/hats_service.cc
+++ b/chrome/browser/ui/hats/hats_service.cc
@@ -8,10 +8,12 @@
 
 #include "base/metrics/field_trial_params.h"
 #include "base/rand_util.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/chrome_features.h"
+#include "components/metrics_services_manager/metrics_services_manager.h"
 
 namespace {
 // Which survey we're triggering
@@ -57,6 +59,11 @@
 }
 
 bool HatsService::ShouldShowSurvey(const std::string& trigger) const {
+  bool consent_given =
+      g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven();
+  if (!consent_given)
+    return false;
+
   if ((trigger_ == trigger || trigger_ == kHatsSurveyTriggerDefault) &&
       !launch_hats_) {
     if (base::RandDouble() < probability_) {
diff --git a/chrome/browser/ui/hats/hats_service_browsertest.cc b/chrome/browser/ui/hats/hats_service_browsertest.cc
index 4c3c371b..c7df0e7 100644
--- a/chrome/browser/ui/hats/hats_service_browsertest.cc
+++ b/chrome/browser/ui/hats/hats_service_browsertest.cc
@@ -5,16 +5,38 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/metrics/user_metrics.h"
+#include "base/optional.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/hats/hats_service.h"
 #include "chrome/browser/ui/hats/hats_service_factory.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "components/metrics_services_manager/metrics_services_manager.h"
 #include "content/public/test/browser_test.h"
 
 namespace {
 
+class ScopedEnableMetricsConsent {
+ public:
+  ScopedEnableMetricsConsent() {
+    ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
+        &enable_metrics_consent_);
+  }
+
+  ~ScopedEnableMetricsConsent() {
+    ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
+        nullptr);
+  }
+
+ private:
+  const bool enable_metrics_consent_ = true;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedEnableMetricsConsent);
+};
+
 class HatsServiceBrowserTestBase : public InProcessBrowserTest {
  protected:
   HatsServiceBrowserTestBase()
@@ -35,6 +57,8 @@
     return HatsServiceFactory::GetForProfile(browser()->profile(), true);
   }
 
+  void EnableMetricsConsent() { enable_metrics_consent_.emplace(); }
+
   bool HatsDialogShowRequested() { return hats_dialog_show_requested_; }
 
  private:
@@ -47,6 +71,7 @@
 
   bool hats_dialog_show_requested_ = false;
   base::ActionCallback on_hats_dialog_show_;
+  base::Optional<ScopedEnableMetricsConsent> enable_metrics_consent_;
 
   DISALLOW_COPY_AND_ASSIGN(HatsServiceBrowserTestBase);
 };
@@ -117,7 +142,17 @@
 
 }  // namespace
 
+IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, NoShowConsentNotGiven) {
+  ASSERT_FALSE(
+      g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
+  GetHatsService()->LaunchSatisfactionSurvey();
+  EXPECT_FALSE(HatsDialogShowRequested());
+}
+
 IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, AlwaysShow) {
+  EnableMetricsConsent();
+  ASSERT_TRUE(
+      g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
   GetHatsService()->LaunchSatisfactionSurvey();
   EXPECT_TRUE(HatsDialogShowRequested());
 }
diff --git a/chrome/browser/ui/login/login_handler.cc b/chrome/browser/ui/login/login_handler.cc
index b4b5540..947fd1a 100644
--- a/chrome/browser/ui/login/login_handler.cc
+++ b/chrome/browser/ui/login/login_handler.cc
@@ -103,6 +103,11 @@
 }
 
 LoginHandler::~LoginHandler() {
+  password_manager::HttpAuthManager* http_auth_manager =
+      GetHttpAuthManagerForLogin();
+  if (http_auth_manager)
+    http_auth_manager->OnPasswordFormDismissed();
+
   if (!WasAuthHandled()) {
     auth_required_callback_.Reset();
 
diff --git a/chrome/browser/ui/page_action/page_action_icon_container.h b/chrome/browser/ui/page_action/page_action_icon_container.h
index bea765d..e75e878 100644
--- a/chrome/browser/ui/page_action/page_action_icon_container.h
+++ b/chrome/browser/ui/page_action/page_action_icon_container.h
@@ -19,6 +19,7 @@
   kTranslate,
   kZoom,
   kNativeFileSystemAccess,
+  kClickToCall,
 };
 
 class PageActionIconContainer {
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
index 059df2b..1daaef3 100644
--- a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
@@ -483,7 +483,7 @@
       std::make_unique<ChromeWebContentsHandler>());
   views::Widget::InitParams init_params(
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
-  init_params.keep_on_top = true;
+  init_params.z_order = ui::ZOrderLevel::kFloatingWindow;
   views::WebDialogView* web_view = view.release();
   init_params.name = "GCPW";  // Used for debugging only.
   init_params.delegate = web_view;
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
index 1bb22d5..337c1fa 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
@@ -120,7 +120,8 @@
     if (IsFrameless())
       init_params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
   }
-  init_params.keep_on_top = create_params.always_on_top;
+  if (create_params.always_on_top)
+    init_params.z_order = ui::ZOrderLevel::kFloatingWindow;
   init_params.visible_on_all_workspaces =
       create_params.visible_on_all_workspaces;
 
@@ -205,8 +206,8 @@
   return ui::SHOW_STATE_NORMAL;
 }
 
-bool ChromeNativeAppWindowViews::IsAlwaysOnTop() const {
-  return widget()->IsAlwaysOnTop();
+ui::ZOrderLevel ChromeNativeAppWindowViews::GetZOrderLevel() const {
+  return widget()->GetZOrderLevel();
 }
 
 // views::WidgetDelegate implementation.
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h
index 50a2422..9398263 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h
@@ -39,7 +39,7 @@
   // ui::BaseWindow implementation.
   gfx::Rect GetRestoredBounds() const override;
   ui::WindowShowState GetRestoredState() const override;
-  bool IsAlwaysOnTop() const override;
+  ui::ZOrderLevel GetZOrderLevel() const override;
 
   // WidgetDelegate implementation.
   gfx::ImageSkia GetWindowAppIcon() override;
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
index d97a1df..695e59c 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
@@ -105,8 +105,8 @@
   return GetRestorableState(restore_state);
 }
 
-bool ChromeNativeAppWindowViewsAura::IsAlwaysOnTop() const {
-  return widget()->IsAlwaysOnTop();
+ui::ZOrderLevel ChromeNativeAppWindowViewsAura::GetZOrderLevel() const {
+  return widget()->GetZOrderLevel();
 }
 
 void ChromeNativeAppWindowViewsAura::UpdateShape(
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.h
index 229eeb1..07801e5 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.h
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.h
@@ -33,7 +33,7 @@
 
   // ui::BaseWindow implementation.
   ui::WindowShowState GetRestoredState() const override;
-  bool IsAlwaysOnTop() const override;
+  ui::ZOrderLevel GetZOrderLevel() const override;
 
   // NativeAppWindow implementation.
   void UpdateShape(std::unique_ptr<ShapeRects> rects) override;
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
index 467a359..eef33b99 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/ui/ash/ash_util.h"
-#include "chrome/browser/ui/ash/kiosk_next_shell_client.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_context_menu.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
@@ -63,13 +62,6 @@
          state == SessionState::LOGIN_SECONDARY;
 }
 
-// Return true if |app_window| is a Kiosk Next Home app in a KioskNext session.
-bool IsKioskNextHomeWindow(const AppWindow* app_window) {
-  return KioskNextShellClient::Get() &&
-         KioskNextShellClient::Get()->has_launched() &&
-         app_window->extension_id() == extension_misc::kKioskNextHomeAppId;
-}
-
 }  // namespace
 
 ChromeNativeAppWindowViewsAuraAsh::ChromeNativeAppWindowViewsAuraAsh()
@@ -120,8 +112,6 @@
     container_id = ash::kShellWindowId_ImeWindowParentContainer;
   else if (create_params.show_on_lock_screen)
     container_id = ash::kShellWindowId_LockActionHandlerContainer;
-  else if (IsKioskNextHomeWindow(app_window()))
-    container_id = ash::kShellWindowId_HomeScreenContainer;
 
   if (container_id.has_value()) {
     ash_util::SetupWidgetInitParamsForContainer(init_params, *container_id);
@@ -212,8 +202,8 @@
   return GetRestorableState(restore_state);
 }
 
-bool ChromeNativeAppWindowViewsAuraAsh::IsAlwaysOnTop() const {
-  return widget()->IsAlwaysOnTop();
+ui::ZOrderLevel ChromeNativeAppWindowViewsAuraAsh::GetZOrderLevel() const {
+  return widget()->GetZOrderLevel();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h
index d729967..44649449 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h
@@ -62,7 +62,7 @@
   // ui::BaseWindow:
   gfx::Rect GetRestoredBounds() const override;
   ui::WindowShowState GetRestoredState() const override;
-  bool IsAlwaysOnTop() const override;
+  ui::ZOrderLevel GetZOrderLevel() const override;
 
   // views::ContextMenuController:
   void ShowContextMenuForViewImpl(views::View* source,
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 41e26f3..a598ed4 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -706,11 +706,11 @@
   frame_->FlashFrame(flash);
 }
 
-bool BrowserView::IsAlwaysOnTop() const {
-  return false;
+ui::ZOrderLevel BrowserView::GetZOrderLevel() const {
+  return ui::ZOrderLevel::kNormal;
 }
 
-void BrowserView::SetAlwaysOnTop(bool always_on_top) {
+void BrowserView::SetZOrderLevel(ui::ZOrderLevel level) {
   // Not implemented for browser windows.
   NOTIMPLEMENTED();
 }
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index a7dc6e3..ec20ded 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -290,8 +290,8 @@
   void Deactivate() override;
   bool IsActive() const override;
   void FlashFrame(bool flash) override;
-  bool IsAlwaysOnTop() const override;
-  void SetAlwaysOnTop(bool always_on_top) override;
+  ui::ZOrderLevel GetZOrderLevel() const override;
+  void SetZOrderLevel(ui::ZOrderLevel order) override;
   gfx::NativeWindow GetNativeWindow() const override;
   void SetTopControlsShownRatio(content::WebContents* web_contents,
                                 float ratio) override;
diff --git a/chrome/browser/ui/views/ime/ime_window_view.cc b/chrome/browser/ui/views/ime/ime_window_view.cc
index e6516d8..2a14d10 100644
--- a/chrome/browser/ui/views/ime/ime_window_view.cc
+++ b/chrome/browser/ui/views/ime/ime_window_view.cc
@@ -38,7 +38,7 @@
   params.delegate = this;
   params.wants_mouse_events_when_inactive = true;
   params.remove_standard_frame = false;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingWindow;
   params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
   params.visible_on_all_workspaces = false;
   params.bounds = bounds;
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index 9bc1f70..993ff8e 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -314,6 +314,9 @@
 }
 
 void IconLabelBubbleView::AnimationEnded(const gfx::Animation* animation) {
+  if (animation != &slide_animation_)
+    return views::LabelButton::AnimationEnded(animation);
+
   if (!is_animation_paused_) {
     // If there is no separator to show, then that means we want the text to
     // disappear after animating.
@@ -326,11 +329,17 @@
 }
 
 void IconLabelBubbleView::AnimationProgressed(const gfx::Animation* animation) {
+  if (animation != &slide_animation_)
+    return views::LabelButton::AnimationProgressed(animation);
+
   if (!is_animation_paused_)
     PreferredSizeChanged();
 }
 
 void IconLabelBubbleView::AnimationCanceled(const gfx::Animation* animation) {
+  if (animation != &slide_animation_)
+    return views::LabelButton::AnimationCanceled(animation);
+
   AnimationEnded(animation);
 }
 
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index e3a8db2..a47ae57 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h"
 #include "chrome/browser/send_tab_to_self/send_tab_to_self_util.h"
+#include "chrome/browser/sharing/click_to_call/feature.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
@@ -229,6 +230,8 @@
     // the left most icon.
     if (send_tab_to_self::IsSendingEnabled())
       params.types_enabled.push_back(PageActionIconType::kSendTabToSelf);
+    if (base::FeatureList::IsEnabled(kClickToCallUI))
+      params.types_enabled.push_back(PageActionIconType::kClickToCall);
     if (!base::FeatureList::IsEnabled(
             autofill::features::kAutofillEnableToolbarStatusChip)) {
       params.types_enabled.push_back(PageActionIconType::kManagePasswords);
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index f5bae7b..58dd745 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -233,7 +233,7 @@
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.bounds = CalculateAndUpdateWindowBounds();
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingWindow;
   params.visible_on_all_workspaces = true;
   params.remove_standard_frame = true;
   params.name = "PictureInPictureWindow";
diff --git a/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.cc b/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.cc
index 250ba4d..0404911 100644
--- a/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.cc
+++ b/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/views/passwords/manage_passwords_icon_views.h"
 #include "chrome/browser/ui/views/reader_mode/reader_mode_icon_view.h"
 #include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.h"
+#include "chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h"
 #include "chrome/browser/ui/views/translate/translate_icon_view.h"
 #include "ui/views/layout/box_layout.h"
 
@@ -86,6 +87,11 @@
             params.page_action_icon_delegate);
         page_action_icons_.push_back(native_file_system_icon_);
         break;
+      case PageActionIconType::kClickToCall:
+        click_to_call_icon_view_ =
+            new ClickToCallIconView(params.page_action_icon_delegate);
+        page_action_icons_.push_back(click_to_call_icon_view_);
+        break;
       case PageActionIconType::kLocalCardMigration:
       case PageActionIconType::kSaveCard:
         NOTREACHED();
@@ -132,6 +138,8 @@
       return send_tab_to_self_icon_view_;
     case PageActionIconType::kNativeFileSystemAccess:
       return native_file_system_icon_;
+    case PageActionIconType::kClickToCall:
+      return click_to_call_icon_view_;
     case PageActionIconType::kLocalCardMigration:
     case PageActionIconType::kSaveCard:
       NOTREACHED();
diff --git a/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h b/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h
index a9177a1..595c91e 100644
--- a/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h
+++ b/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h
@@ -16,6 +16,7 @@
 #include "ui/views/view.h"
 
 class Browser;
+class ClickToCallIconView;
 class CommandUpdater;
 class FindBarIcon;
 class IntentPickerView;
@@ -92,6 +93,7 @@
   TranslateIconView* translate_icon_ = nullptr;
   NativeFileSystemAccessIconView* native_file_system_icon_ = nullptr;
   ReaderModeIconView* reader_mode_icon_ = nullptr;
+  ClickToCallIconView* click_to_call_icon_view_ = nullptr;
   std::vector<PageActionIconView*> page_action_icons_;
 
   ScopedObserver<zoom::ZoomEventManager, zoom::ZoomEventManagerObserver>
diff --git a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
index 0d4e2304..e66ede2 100644
--- a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
+++ b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
@@ -196,7 +196,7 @@
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.remove_standard_frame = true;
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.name = "ScreenCaptureNotificationUIViews";
 
 #if defined(OS_CHROMEOS)
@@ -208,7 +208,6 @@
 
   widget->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM);
   widget->Init(params);
-  widget->SetAlwaysOnTop(true);
 
   SetBackground(views::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
       ui::NativeTheme::kColorId_DialogBackground)));
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.cc b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.cc
index e478b20..2de9c33 100644
--- a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.cc
+++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.cc
@@ -3,9 +3,16 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h"
+
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/sharing/sharing_metrics.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
+#include "chrome/browser/ui/views/hover_button.h"
+#include "chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
@@ -13,6 +20,9 @@
 #include "base/logging.h"
 
 namespace {
+// Global instance of the bubble view.
+ClickToCallDialogView* g_bubble_ = nullptr;
+
 // Icon sizes in DIP.
 // TODO: Confirm the number with the team designer.
 constexpr int kPrimaryIconSize = 20;
@@ -44,6 +54,35 @@
 
 }  // namespace
 
+// static
+ClickToCallDialogView* ClickToCallDialogView::GetBubbleView() {
+  return g_bubble_;
+}
+
+// static
+void ClickToCallDialogView::Show(
+    content::WebContents* web_contents,
+    std::unique_ptr<ClickToCallSharingDialogController> controller) {
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+  if (g_bubble_ || !browser)
+    return;
+
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
+  views::View* anchor_view =
+      browser_view->toolbar_button_provider()->GetAnchorView();
+  PageActionIconView* icon =
+      browser_view->toolbar_button_provider()
+          ->GetOmniboxPageActionIconContainerView()
+          ->GetPageActionIconView(PageActionIconType::kClickToCall);
+
+  g_bubble_ = new ClickToCallDialogView(anchor_view, icon, web_contents,
+                                        std::move(controller));
+  views::BubbleDialogDelegateView::CreateBubble(g_bubble_)->Show();
+
+  icon->Update();
+  DCHECK(icon->GetVisible());
+}
+
 ClickToCallDialogView::ClickToCallDialogView(
     views::View* anchor_view,
     PageActionIconView* icon_view,
@@ -104,6 +143,7 @@
       views::BoxLayout::Orientation::kVertical));
   AddChildView(dialog_view);
   // Devices:
+  LogClickToCallDevicesToShow(devices_.size());
   for (const auto& device : devices_) {
     auto dialog_button = std::make_unique<HoverButton>(
         this, CreateDeviceIcon(device.device_type()),
@@ -116,6 +156,7 @@
   }
 
   // Apps:
+  LogClickToCallAppsToShow(apps_.size());
   for (const auto& app : apps_) {
     auto dialog_button = std::make_unique<HoverButton>(this, app.name);
     // TODO(yasmo): Create Icon View.
@@ -143,3 +184,9 @@
 base::string16 ClickToCallDialogView::GetWindowTitle() const {
   return base::UTF8ToUTF16(controller_->GetTitle());
 }
+
+void ClickToCallDialogView::WindowClosing() {
+  DCHECK_EQ(g_bubble_, this);
+  g_bubble_ = nullptr;
+  icon_view_->Update();
+}
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h
index 61b84a5..da44816 100644
--- a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h
+++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h
@@ -6,28 +6,28 @@
 #define CHROME_BROWSER_UI_VIEWS_SHARING_CLICK_TO_CALL_CLICK_TO_CALL_DIALOG_VIEW_H_
 
 #include <memory>
-#include <string>
 #include <vector>
 
 #include "chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller.h"
 #include "chrome/browser/sharing/sharing_device_info.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
-#include "chrome/browser/ui/views/hover_button.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
-#include "chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h"
 #include "ui/views/controls/button/button.h"
 
 namespace views {
 class View;
 }  // namespace views
 
+class HoverButton;
 class PageActionIconView;
 
 class ClickToCallDialogView : public views::ButtonListener,
                               public LocationBarBubbleDelegateView {
  public:
+  static ClickToCallDialogView* GetBubbleView();
+  static void Show(
+      content::WebContents* web_contents,
+      std::unique_ptr<ClickToCallSharingDialogController> controller);
+
   // Bubble will be anchored to |anchor_view|.
   ClickToCallDialogView(
       views::View* anchor_view,
@@ -40,6 +40,7 @@
   // views::WidgetDelegateView:
   bool ShouldShowCloseButton() const override;
   base::string16 GetWindowTitle() const override;
+  void WindowClosing() override;
 
   // views::DialogDelegate:
   int GetDialogButtons() const override;
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view_unittest.cc b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view_unittest.cc
index 56d9918..3931fc7 100644
--- a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view_unittest.cc
+++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/simple_test_clock.h"
+#include "chrome/browser/ui/views/hover_button.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/views/chrome_views_test_base.h"
 #include "components/send_tab_to_self/target_device_info.h"
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc
new file mode 100644
index 0000000..dd6b582
--- /dev/null
+++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc
@@ -0,0 +1,138 @@
+// Copyright 2019 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 "chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h"
+
+#include <algorithm>
+
+#include "base/memory/ptr_util.h"
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/animation/throb_animation.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/scoped_canvas.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/views/animation/ink_drop.h"
+
+namespace {
+// Height of the loader bar in DIP.
+constexpr float kLoaderHeight = 4.0f;
+// Width of the loader bar in percent of its range.
+constexpr float kLoaderWidth = 0.2f;
+}  // namespace
+
+ClickToCallIconView::ClickToCallIconView(PageActionIconView::Delegate* delegate)
+    : PageActionIconView(/*command_updater=*/nullptr,
+                         /*command_id=*/0,
+                         delegate) {
+  SetVisible(false);
+  UpdateLoaderColor();
+}
+
+ClickToCallIconView::~ClickToCallIconView() = default;
+
+views::BubbleDialogDelegateView* ClickToCallIconView::GetBubble() const {
+  return ClickToCallDialogView::GetBubbleView();
+}
+
+bool ClickToCallIconView::Update() {
+  const bool is_bubble_showing = IsBubbleShowing();
+  const bool is_visible = is_bubble_showing || loading_animation_;
+  const bool visibility_changed = GetVisible() != is_visible;
+  SetVisible(is_visible);
+  UpdateInkDrop(is_bubble_showing);
+  return visibility_changed;
+}
+
+void ClickToCallIconView::StartLoadingAnimation() {
+  if (loading_animation_)
+    return;
+  loading_animation_ = std::make_unique<gfx::ThrobAnimation>(this);
+  loading_animation_->SetTweenType(gfx::Tween::LINEAR);
+  loading_animation_->SetThrobDuration(750);
+  loading_animation_->StartThrobbing(-1);
+  SchedulePaint();
+}
+
+void ClickToCallIconView::StopLoadingAnimation() {
+  if (!loading_animation_)
+    return;
+  loading_animation_.reset();
+  SchedulePaint();
+}
+
+void ClickToCallIconView::PaintButtonContents(gfx::Canvas* canvas) {
+  PageActionIconView::PaintButtonContents(canvas);
+  if (!loading_animation_)
+    return;
+
+  // TODO(knollr): Add support for this animation to PageActionIconView if other
+  // features need it as well.
+
+  gfx::ScopedCanvas scoped_canvas(canvas);
+  const float scale = canvas->UndoDeviceScaleFactor();
+  const gfx::Rect icon_bounds =
+      gfx::ScaleToEnclosedRect(image()->bounds(), scale);
+  const float progress = loading_animation_->GetCurrentValue();
+  const float range = icon_bounds.width();
+  const float offset = icon_bounds.x();
+
+  // Calculate start and end in percent of range.
+  float start = std::max(0.0f, (progress - kLoaderWidth) / (1 - kLoaderWidth));
+  float end = std::min(1.0f, progress / (1 - kLoaderWidth));
+  // Convert percentages to actual location.
+  start = start * (range - kLoaderHeight);
+  end = end * (range - kLoaderHeight) + kLoaderHeight;
+
+  gfx::RectF bounds(start + offset, icon_bounds.bottom() - kLoaderHeight,
+                    end - start, kLoaderHeight);
+
+  cc::PaintFlags flags;
+  flags.setAntiAlias(true);
+  flags.setStyle(cc::PaintFlags::kFill_Style);
+  flags.setColor(loader_color_);
+  canvas->DrawRoundRect(bounds, bounds.height() / 2, flags);
+}
+
+void ClickToCallIconView::AnimationProgressed(const gfx::Animation* animation) {
+  if (animation != loading_animation_.get())
+    return PageActionIconView::AnimationProgressed(animation);
+  SchedulePaint();
+}
+
+void ClickToCallIconView::OnThemeChanged() {
+  PageActionIconView::OnThemeChanged();
+  UpdateLoaderColor();
+}
+
+void ClickToCallIconView::UpdateInkDrop(bool activate) {
+  auto target_state =
+      activate ? views::InkDropState::ACTIVATED : views::InkDropState::HIDDEN;
+  if (GetInkDrop()->GetTargetInkDropState() != target_state)
+    AnimateInkDrop(target_state, /*event=*/nullptr);
+}
+
+void ClickToCallIconView::UpdateLoaderColor() {
+  loader_color_ = GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_ProminentButtonColor);
+}
+
+bool ClickToCallIconView::IsTriggerableEvent(const ui::Event& event) {
+  // We do nothing when the icon is clicked.
+  return false;
+}
+
+void ClickToCallIconView::OnExecuting(
+    PageActionIconView::ExecuteSource execute_source) {}
+
+const gfx::VectorIcon& ClickToCallIconView::GetVectorIcon() const {
+  // TODO(crbug.com/972059): Should we have our own icon?
+  return kSendTabToSelfIcon;
+}
+
+base::string16 ClickToCallIconView::GetTextForTooltipAndAccessibleName() const {
+  return l10n_util::GetStringUTF16(
+      IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TITLE_LABEL);
+}
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h
new file mode 100644
index 0000000..3721c17
--- /dev/null
+++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h
@@ -0,0 +1,65 @@
+// Copyright 2019 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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_SHARING_CLICK_TO_CALL_CLICK_TO_CALL_ICON_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_SHARING_CLICK_TO_CALL_CLICK_TO_CALL_ICON_VIEW_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/vector_icon_types.h"
+
+namespace gfx {
+class Canvas;
+class ThrobAnimation;
+}  // namespace gfx
+
+namespace ui {
+class Event;
+}  // namespace ui
+
+// The location bar icon to show the click to call bubble where the user can
+// choose to send a phone number to a target device or use an OS handler app.
+class ClickToCallIconView : public PageActionIconView {
+ public:
+  explicit ClickToCallIconView(PageActionIconView::Delegate* delegate);
+  ~ClickToCallIconView() override;
+
+  // PageActionIconView:
+  views::BubbleDialogDelegateView* GetBubble() const override;
+  bool Update() override;
+  base::string16 GetTextForTooltipAndAccessibleName() const override;
+
+  // views::Button:
+  void PaintButtonContents(gfx::Canvas* canvas) override;
+
+  // views::View:
+  void OnThemeChanged() override;
+
+  void StartLoadingAnimation();
+  void StopLoadingAnimation();
+
+ protected:
+  // PageActionIconView:
+  void OnExecuting(PageActionIconView::ExecuteSource execute_source) override;
+  const gfx::VectorIcon& GetVectorIcon() const override;
+  bool IsTriggerableEvent(const ui::Event& event) override;
+
+  // gfx::AnimationDelegate:
+  void AnimationProgressed(const gfx::Animation* animation) override;
+
+ private:
+  void UpdateInkDrop(bool activate);
+  void UpdateLoaderColor();
+
+  SkColor loader_color_;
+  std::unique_ptr<gfx::ThrobAnimation> loading_animation_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClickToCallIconView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_SHARING_CLICK_TO_CALL_CLICK_TO_CALL_ICON_VIEW_H_
diff --git a/chrome/browser/ui/views/simple_message_box_views.cc b/chrome/browser/ui/views/simple_message_box_views.cc
index 83e16bc..7128fa3 100644
--- a/chrome/browser/ui/views/simple_message_box_views.cc
+++ b/chrome/browser/ui/views/simple_message_box_views.cc
@@ -162,7 +162,7 @@
   // attach to, move the dialog's widget on top so other windows do not obscure
   // it.
   if (!parent)
-    widget->SetAlwaysOnTop(true);
+    widget->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
 #endif
 
   widget->Show();
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 0474a23..cbb3578 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -828,7 +828,8 @@
   std::unique_ptr<aura::Window> masked_window(
       aura::test::CreateTestWindowWithDelegate(
           &masked_window_delegate, 10, bounds, browser_window->parent()));
-  masked_window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  masked_window->SetProperty(aura::client::kZOrderingKey,
+                             ui::ZOrderLevel::kFloatingWindow);
   auto targeter = std::make_unique<aura::WindowTargeter>();
   targeter->SetInsets(gfx::Insets(0, bounds.width() - 10, 0, 0));
   masked_window->SetEventTargeter(std::move(targeter));
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index b249d17..a1f84bc 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -2721,7 +2721,7 @@
 
   arrow_window = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-  params.keep_on_top = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.accept_events = false;
   params.bounds = gfx::Rect(g_drop_indicator_width, g_drop_indicator_height);
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index ca236a0..9352a52 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -357,7 +357,7 @@
 
 void TaskManagerView::InitAlwaysOnTopState() {
   RetrieveSavedAlwaysOnTopState();
-  GetWidget()->SetAlwaysOnTop(is_always_on_top_);
+  GetWidget()->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
 }
 
 void TaskManagerView::ActivateSelectedTab() {
diff --git a/chrome/browser/ui/views/try_chrome_dialog_win/try_chrome_dialog.cc b/chrome/browser/ui/views/try_chrome_dialog_win/try_chrome_dialog.cc
index cca4fae..c8f9491 100644
--- a/chrome/browser/ui/views/try_chrome_dialog_win/try_chrome_dialog.cc
+++ b/chrome/browser/ui/views/try_chrome_dialog_win/try_chrome_dialog.cc
@@ -1193,7 +1193,7 @@
   // This propagation can cause views to change their size requirements.
   const gfx::Size preferred = popup_->GetContentsView()->GetPreferredSize();
   popup_->SetBounds(context_->ComputePopupBounds(popup_, preferred));
-  popup_->SetAlwaysOnTop(true);
+  popup_->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
 
   popup_->ShowInactive();
   delegate_->SetToastLocation(context_->GetToastLocation());
diff --git a/chrome/browser/ui/web_applications/web_app_ui_service.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
similarity index 72%
rename from chrome/browser/ui/web_applications/web_app_ui_service.cc
rename to chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
index dc95e29..a6682c7 100644
--- a/chrome/browser/ui/web_applications/web_app_ui_service.cc
+++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/web_applications/web_app_ui_service.h"
+#include "chrome/browser/ui/web_applications/web_app_ui_manager_impl.h"
 
 #include <utility>
 
@@ -11,7 +11,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_manager.h"
-#include "chrome/browser/ui/web_applications/web_app_ui_service_factory.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 
@@ -23,13 +22,11 @@
 namespace web_app {
 
 // static
-WebAppUiService* WebAppUiService::Get(Profile* profile) {
-  return WebAppUiServiceFactory::GetForProfile(profile);
+std::unique_ptr<WebAppUiManager> WebAppUiManager::Create(Profile* profile) {
+  return std::make_unique<WebAppUiManagerImpl>(profile);
 }
 
-WebAppUiService::WebAppUiService(Profile* profile) : profile_(profile) {
-  provider_ = WebAppProvider::Get(profile_);
-
+WebAppUiManagerImpl::WebAppUiManagerImpl(Profile* profile) : profile_(profile) {
   for (Browser* browser : *BrowserList::GetInstance()) {
     base::Optional<AppId> app_id = GetAppIdForBrowser(browser);
     if (!app_id.has_value())
@@ -39,20 +36,19 @@
   }
 
   BrowserList::AddObserver(this);
-  provider_->set_ui_delegate(this);
 
   dialog_manager_ = std::make_unique<WebAppDialogManager>(profile);
 }
 
-WebAppUiService::~WebAppUiService() {
-  provider_->set_ui_delegate(nullptr);
-}
-
-void WebAppUiService::Shutdown() {
+WebAppUiManagerImpl::~WebAppUiManagerImpl() {
   BrowserList::RemoveObserver(this);
 }
 
-size_t WebAppUiService::GetNumWindowsForApp(const AppId& app_id) {
+WebAppDialogManager& WebAppUiManagerImpl::dialog_manager() {
+  return *dialog_manager_;
+}
+
+size_t WebAppUiManagerImpl::GetNumWindowsForApp(const AppId& app_id) {
   auto it = num_windows_for_apps_map_.find(app_id);
   if (it == num_windows_for_apps_map_.end())
     return 0;
@@ -60,8 +56,9 @@
   return it->second;
 }
 
-void WebAppUiService::NotifyOnAllAppWindowsClosed(const AppId& app_id,
-                                                  base::OnceClosure callback) {
+void WebAppUiManagerImpl::NotifyOnAllAppWindowsClosed(
+    const AppId& app_id,
+    base::OnceClosure callback) {
   const size_t num_windows_for_app = GetNumWindowsForApp(app_id);
   if (num_windows_for_app == 0) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
@@ -72,14 +69,15 @@
   windows_closed_requests_map_[app_id].push_back(std::move(callback));
 }
 
-void WebAppUiService::MigrateOSAttributes(const AppId& from, const AppId& to) {
+void WebAppUiManagerImpl::MigrateOSAttributes(const AppId& from,
+                                              const AppId& to) {
 #if defined(OS_CHROMEOS)
   app_list::AppListSyncableServiceFactory::GetForProfile(profile_)
       ->TransferItemAttributes(from, to);
 #endif
 }
 
-void WebAppUiService::OnBrowserAdded(Browser* browser) {
+void WebAppUiManagerImpl::OnBrowserAdded(Browser* browser) {
   base::Optional<AppId> app_id = GetAppIdForBrowser(browser);
   if (!app_id.has_value())
     return;
@@ -87,7 +85,7 @@
   ++num_windows_for_apps_map_[app_id.value()];
 }
 
-void WebAppUiService::OnBrowserRemoved(Browser* browser) {
+void WebAppUiManagerImpl::OnBrowserRemoved(Browser* browser) {
   base::Optional<AppId> app_id_opt = GetAppIdForBrowser(browser);
   if (!app_id_opt.has_value())
     return;
@@ -111,7 +109,8 @@
   windows_closed_requests_map_.erase(app_id);
 }
 
-base::Optional<AppId> WebAppUiService::GetAppIdForBrowser(Browser* browser) {
+base::Optional<AppId> WebAppUiManagerImpl::GetAppIdForBrowser(
+    Browser* browser) {
   if (browser->profile() != profile_)
     return base::nullopt;
 
diff --git a/chrome/browser/ui/web_applications/web_app_ui_service.h b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
similarity index 60%
rename from chrome/browser/ui/web_applications/web_app_ui_service.h
rename to chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
index 5bf41cc..6e2c2c6 100644
--- a/chrome/browser/ui/web_applications/web_app_ui_service.h
+++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_SERVICE_H_
-#define CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_SERVICE_H_
+#ifndef CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_MANAGER_IMPL_H_
+#define CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_MANAGER_IMPL_H_
 
 #include <map>
 #include <memory>
@@ -14,8 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "chrome/browser/ui/browser_list_observer.h"
-#include "chrome/browser/web_applications/components/web_app_ui_delegate.h"
-#include "components/keyed_service/core/keyed_service.h"
+#include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 
 class Profile;
 class Browser;
@@ -26,27 +25,21 @@
 class WebAppDialogManager;
 
 // This KeyedService is a UI counterpart for WebAppProvider.
-class WebAppUiService : public KeyedService,
-                        public BrowserListObserver,
-                        public WebAppUiDelegate {
+class WebAppUiManagerImpl : public BrowserListObserver, public WebAppUiManager {
  public:
-  static WebAppUiService* Get(Profile* profile);
+  static WebAppUiManagerImpl* Get(Profile* profile);
 
-  explicit WebAppUiService(Profile* profile);
-  ~WebAppUiService() override;
+  explicit WebAppUiManagerImpl(Profile* profile);
+  ~WebAppUiManagerImpl() override;
 
-  // KeyedService
-  void Shutdown() override;
-
-  WebAppDialogManager& dialog_manager() { return *dialog_manager_; }
-
-  // WebAppUiDelegate
+  // WebAppUiManager:
+  WebAppDialogManager& dialog_manager() override;
   size_t GetNumWindowsForApp(const AppId& app_id) override;
   void NotifyOnAllAppWindowsClosed(const AppId& app_id,
                                    base::OnceClosure callback) override;
   void MigrateOSAttributes(const AppId& from, const AppId& to) override;
 
-  // BrowserListObserver
+  // BrowserListObserver:
   void OnBrowserAdded(Browser* browser) override;
   void OnBrowserRemoved(Browser* browser) override;
 
@@ -55,17 +48,16 @@
 
   std::unique_ptr<WebAppDialogManager> dialog_manager_;
 
-  WebAppProvider* provider_;
   Profile* profile_;
 
   std::map<AppId, std::vector<base::OnceClosure>> windows_closed_requests_map_;
   std::map<AppId, size_t> num_windows_for_apps_map_;
 
-  base::WeakPtrFactory<WebAppUiService> weak_ptr_factory_{this};
+  base::WeakPtrFactory<WebAppUiManagerImpl> weak_ptr_factory_{this};
 
-  DISALLOW_COPY_AND_ASSIGN(WebAppUiService);
+  DISALLOW_COPY_AND_ASSIGN(WebAppUiManagerImpl);
 };
 
 }  // namespace web_app
 
-#endif  // CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_SERVICE_H_
+#endif  // CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_MANAGER_IMPL_H_
diff --git a/chrome/browser/ui/web_applications/web_app_ui_service_browsertest.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc
similarity index 80%
rename from chrome/browser/ui/web_applications/web_app_ui_service_browsertest.cc
rename to chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc
index 653be5e..c4cc9b3 100644
--- a/chrome/browser/ui/web_applications/web_app_ui_service_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/web_applications/web_app_ui_service.h"
+#include "chrome/browser/ui/web_applications/web_app_ui_manager_impl.h"
 
 #include "base/barrier_closure.h"
 #include "base/test/bind_test_util.h"
@@ -72,7 +72,7 @@
 const GURL kFooUrl = GURL("https://foo.example");
 const GURL kBarUrl = GURL("https://bar.example");
 
-class WebAppUiServiceBrowserTest : public InProcessBrowserTest {
+class WebAppUiManagerImplBrowserTest : public InProcessBrowserTest {
  protected:
   Profile* profile() { return browser()->profile(); }
 
@@ -88,28 +88,25 @@
     return extensions::browsertest_util::LaunchAppBrowser(profile(), app);
   }
 
-  WebAppUiService* ui_service() { return WebAppUiService::Get(profile()); }
+  WebAppUiManager& ui_manager() {
+    return WebAppProviderBase::GetProviderBase(profile())->ui_manager();
+  }
 };
 
-IN_PROC_BROWSER_TEST_F(WebAppUiServiceBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAppUiManagerImplBrowserTest,
                        GetNumWindowsForApp_AppWindowsAdded) {
-  // Should not crash.
-  auto& ui_delegate = WebAppProvider::Get(browser()->profile())->ui_delegate();
-  auto* ui_service = WebAppUiService::Get(browser()->profile());
-  EXPECT_EQ(&ui_delegate, ui_service);
-
   // Zero apps on start:
-  EXPECT_EQ(0u, ui_service->GetNumWindowsForApp(AppId()));
+  EXPECT_EQ(0u, ui_manager().GetNumWindowsForApp(AppId()));
 
   const auto* foo_app = InstallWebApp(kFooUrl);
   LaunchApp(foo_app);
-  EXPECT_EQ(1u, ui_service->GetNumWindowsForApp(foo_app->id()));
+  EXPECT_EQ(1u, ui_manager().GetNumWindowsForApp(foo_app->id()));
 
   LaunchApp(foo_app);
-  EXPECT_EQ(2u, ui_service->GetNumWindowsForApp(foo_app->id()));
+  EXPECT_EQ(2u, ui_manager().GetNumWindowsForApp(foo_app->id()));
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppUiServiceBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAppUiManagerImplBrowserTest,
                        GetNumWindowsForApp_AppWindowsRemoved) {
   const auto* foo_app = InstallWebApp(kFooUrl);
   auto* foo_window1 = LaunchApp(foo_app);
@@ -118,21 +115,21 @@
   const auto* bar_app = InstallWebApp(kBarUrl);
   LaunchApp(bar_app);
 
-  EXPECT_EQ(2u, ui_service()->GetNumWindowsForApp(foo_app->id()));
-  EXPECT_EQ(1u, ui_service()->GetNumWindowsForApp(bar_app->id()));
+  EXPECT_EQ(2u, ui_manager().GetNumWindowsForApp(foo_app->id()));
+  EXPECT_EQ(1u, ui_manager().GetNumWindowsForApp(bar_app->id()));
 
   CloseAndWait(foo_window1);
 
-  EXPECT_EQ(1u, ui_service()->GetNumWindowsForApp(foo_app->id()));
-  EXPECT_EQ(1u, ui_service()->GetNumWindowsForApp(bar_app->id()));
+  EXPECT_EQ(1u, ui_manager().GetNumWindowsForApp(foo_app->id()));
+  EXPECT_EQ(1u, ui_manager().GetNumWindowsForApp(bar_app->id()));
 
   CloseAndWait(foo_window2);
 
-  EXPECT_EQ(0u, ui_service()->GetNumWindowsForApp(foo_app->id()));
-  EXPECT_EQ(1u, ui_service()->GetNumWindowsForApp(bar_app->id()));
+  EXPECT_EQ(0u, ui_manager().GetNumWindowsForApp(foo_app->id()));
+  EXPECT_EQ(1u, ui_manager().GetNumWindowsForApp(bar_app->id()));
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppUiServiceBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAppUiManagerImplBrowserTest,
                        NotifyOnAllAppWindowsClosed_NoOpenedWindows) {
   const auto* foo_app = InstallWebApp(kFooUrl);
   const auto* bar_app = InstallWebApp(kBarUrl);
@@ -140,14 +137,14 @@
 
   base::RunLoop run_loop;
   // Should return early; no windows for |foo_app|.
-  ui_service()->NotifyOnAllAppWindowsClosed(foo_app->id(),
-                                            run_loop.QuitClosure());
+  ui_manager().NotifyOnAllAppWindowsClosed(foo_app->id(),
+                                           run_loop.QuitClosure());
   run_loop.Run();
 }
 
 // Tests that the callback is correctly called when there is more than one
 // app window.
-IN_PROC_BROWSER_TEST_F(WebAppUiServiceBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAppUiManagerImplBrowserTest,
                        NotifyOnAllAppWindowsClosed_MultipleOpenedWindows) {
   const auto* foo_app = InstallWebApp(kFooUrl);
   const auto* bar_app = InstallWebApp(kBarUrl);
@@ -161,11 +158,11 @@
 
     bool callback_ran = false;
     base::RunLoop run_loop;
-    ui_service()->NotifyOnAllAppWindowsClosed(foo_app->id(),
-                                              base::BindLambdaForTesting([&]() {
-                                                callback_ran = true;
-                                                run_loop.Quit();
-                                              }));
+    ui_manager().NotifyOnAllAppWindowsClosed(foo_app->id(),
+                                             base::BindLambdaForTesting([&]() {
+                                               callback_ran = true;
+                                               run_loop.Quit();
+                                             }));
 
     CloseAndWait(foo_window1);
     // The callback shouldn't have run yet because there is still one window
@@ -182,12 +179,13 @@
 }
 
 #if defined(OS_CHROMEOS)
-class WebAppUiServiceMigrationBrowserTest : public WebAppUiServiceBrowserTest {
+class WebAppUiServiceMigrationBrowserTest
+    : public WebAppUiManagerImplBrowserTest {
  public:
   void SetUp() override {
     // Disable System Web Apps so that the Internal Apps are installed.
     scoped_feature_list_.InitAndDisableFeature(features::kSystemWebApps);
-    WebAppUiServiceBrowserTest::SetUp();
+    WebAppUiManagerImplBrowserTest::SetUp();
   }
 
  private:
diff --git a/chrome/browser/ui/web_applications/web_app_ui_service_factory.cc b/chrome/browser/ui/web_applications/web_app_ui_service_factory.cc
deleted file mode 100644
index 1c2cb9d..0000000
--- a/chrome/browser/ui/web_applications/web_app_ui_service_factory.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2019 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 "chrome/browser/ui/web_applications/web_app_ui_service_factory.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/web_applications/web_app_ui_service.h"
-#include "chrome/browser/web_applications/components/web_app_utils.h"
-#include "chrome/browser/web_applications/web_app_provider_factory.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
-#endif
-
-namespace web_app {
-
-// static
-WebAppUiService* WebAppUiServiceFactory::GetForProfile(Profile* profile) {
-  return static_cast<WebAppUiService*>(
-      WebAppUiServiceFactory::GetInstance()->GetServiceForBrowserContext(
-          profile, true /* create */));
-}
-
-// static
-WebAppUiServiceFactory* WebAppUiServiceFactory::GetInstance() {
-  return base::Singleton<WebAppUiServiceFactory>::get();
-}
-
-WebAppUiServiceFactory::WebAppUiServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "WebAppUiService",
-          BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(WebAppProviderFactory::GetInstance());
-#if defined(OS_CHROMEOS)
-  DependsOn(app_list::AppListSyncableServiceFactory::GetInstance());
-#endif
-}
-
-WebAppUiServiceFactory::~WebAppUiServiceFactory() = default;
-
-KeyedService* WebAppUiServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  return new WebAppUiService(Profile::FromBrowserContext(context));
-}
-
-bool WebAppUiServiceFactory::ServiceIsCreatedWithBrowserContext() const {
-  return true;
-}
-
-content::BrowserContext* WebAppUiServiceFactory::GetBrowserContextToUse(
-    content::BrowserContext* context) const {
-  return GetBrowserContextForWebApps(context);
-}
-
-}  // namespace web_app
diff --git a/chrome/browser/ui/web_applications/web_app_ui_service_factory.h b/chrome/browser/ui/web_applications/web_app_ui_service_factory.h
deleted file mode 100644
index 1f5683c..0000000
--- a/chrome/browser/ui/web_applications/web_app_ui_service_factory.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_SERVICE_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-namespace content {
-class BrowserContext;
-}
-
-class Profile;
-
-namespace web_app {
-
-class WebAppUiService;
-
-// Singleton that owns all WebAppUiServices and associates them
-// with Profile.
-class WebAppUiServiceFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static WebAppUiService* GetForProfile(Profile* profile);
-
-  static WebAppUiServiceFactory* GetInstance();
-
- private:
-  friend struct base::DefaultSingletonTraits<WebAppUiServiceFactory>;
-
-  WebAppUiServiceFactory();
-  ~WebAppUiServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-  bool ServiceIsCreatedWithBrowserContext() const override;
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(WebAppUiServiceFactory);
-};
-
-}  // namespace web_app
-
-#endif  // CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ui/webui/chromeos/account_manager_welcome_dialog.cc b/chrome/browser/ui/webui/chromeos/account_manager_welcome_dialog.cc
index ae19e2b..d678bfe 100644
--- a/chrome/browser/ui/webui/chromeos/account_manager_welcome_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/account_manager_welcome_dialog.cc
@@ -66,7 +66,7 @@
 
 void AccountManagerWelcomeDialog::AdjustWidgetInitParams(
     views::Widget::InitParams* params) {
-  params->keep_on_top = false;
+  params->z_order = ui::ZOrderLevel::kNormal;
   params->type = views::Widget::InitParams::Type::TYPE_WINDOW_FRAMELESS;
   params->shadow_type = views::Widget::InitParams::ShadowType::SHADOW_TYPE_DROP;
   params->shadow_elevation = wm::kShadowElevationActiveWindow;
diff --git a/chrome/browser/ui/webui/chromeos/account_migration_welcome_dialog.cc b/chrome/browser/ui/webui/chromeos/account_migration_welcome_dialog.cc
index 51ff02f..3340773 100644
--- a/chrome/browser/ui/webui/chromeos/account_migration_welcome_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/account_migration_welcome_dialog.cc
@@ -63,7 +63,7 @@
 
 void AccountMigrationWelcomeDialog::AdjustWidgetInitParams(
     views::Widget::InitParams* params) {
-  params->keep_on_top = false;
+  params->z_order = ui::ZOrderLevel::kNormal;
   params->type = views::Widget::InitParams::Type::TYPE_WINDOW_FRAMELESS;
   params->shadow_type = views::Widget::InitParams::ShadowType::SHADOW_TYPE_DROP;
   params->shadow_elevation = wm::kShadowElevationActiveWindow;
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
index f296b04..5a7d3eb 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
@@ -142,7 +142,7 @@
 
 void AssistantOptInDialog::AdjustWidgetInitParams(
     views::Widget::InitParams* params) {
-  params->keep_on_top = false;
+  params->z_order = ui::ZOrderLevel::kNormal;
 }
 
 void AssistantOptInDialog::GetDialogSize(gfx::Size* size) const {
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc
index b3af756..ce3b17a 100644
--- a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc
+++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc
@@ -81,7 +81,8 @@
   dialog->ShowSystemDialog();
   EXPECT_FALSE(ash::ShellTestApi().IsSystemModalWindowOpen());
   aura::Window* window_to_test = dialog->dialog_window();
-  EXPECT_TRUE(window_to_test->GetProperty(aura::client::kAlwaysOnTopKey));
+  EXPECT_NE(ui::ZOrderLevel::kNormal,
+            window_to_test->GetProperty(aura::client::kZOrderingKey));
 }
 
 using SystemWebDialogTest = InProcessBrowserTest;
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc
index 0d2c11b..6fcd5cd 100644
--- a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc
+++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc
@@ -160,7 +160,7 @@
   views::Widget::InitParams extra_params;
   // If unparented and not modal, keep it on top (see header comment).
   if (!parent && GetDialogModalType() == ui::MODAL_TYPE_NONE)
-    extra_params.keep_on_top = true;
+    extra_params.z_order = ui::ZOrderLevel::kFloatingWindow;
   AdjustWidgetInitParams(&extra_params);
   dialog_window_ = chrome::ShowWebDialogWithParams(parent, browser_context,
                                                    this, &extra_params);
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
index 856ad1a2..3f4e487 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
@@ -49,7 +49,7 @@
 
 void InlineLoginHandlerDialogChromeOS::AdjustWidgetInitParams(
     views::Widget::InitParams* params) {
-  params->keep_on_top = false;
+  params->z_order = ui::ZOrderLevel::kNormal;
 }
 
 gfx::Size InlineLoginHandlerDialogChromeOS::GetMaximumDialogSize() {
diff --git a/chrome/browser/vr/service/arcore_consent_prompt_interface.cc b/chrome/browser/vr/service/arcore_consent_prompt_interface.cc
index b7ecf75..80ece6d9 100644
--- a/chrome/browser/vr/service/arcore_consent_prompt_interface.cc
+++ b/chrome/browser/vr/service/arcore_consent_prompt_interface.cc
@@ -7,17 +7,17 @@
 namespace vr {
 
 namespace {
-ArcoreConsentPromptInterface* g_arcore_consent_prompt = nullptr;
+ArCoreConsentPromptInterface* g_arcore_consent_prompt = nullptr;
 }
 
 // static
-void ArcoreConsentPromptInterface::SetInstance(
-    ArcoreConsentPromptInterface* instance) {
+void ArCoreConsentPromptInterface::SetInstance(
+    ArCoreConsentPromptInterface* instance) {
   g_arcore_consent_prompt = instance;
 }
 
 // static
-ArcoreConsentPromptInterface* ArcoreConsentPromptInterface::GetInstance() {
+ArCoreConsentPromptInterface* ArCoreConsentPromptInterface::GetInstance() {
   return g_arcore_consent_prompt;
 }
 
diff --git a/chrome/browser/vr/service/arcore_consent_prompt_interface.h b/chrome/browser/vr/service/arcore_consent_prompt_interface.h
index 442c908..44249ec 100644
--- a/chrome/browser/vr/service/arcore_consent_prompt_interface.h
+++ b/chrome/browser/vr/service/arcore_consent_prompt_interface.h
@@ -12,10 +12,10 @@
 
 // TODO(crbug.com/968233): Unify consent flow.
 // This class solves layering problem until the above bug gets fixed.
-class VR_EXPORT ArcoreConsentPromptInterface {
+class VR_EXPORT ArCoreConsentPromptInterface {
  public:
-  static void SetInstance(ArcoreConsentPromptInterface*);
-  static ArcoreConsentPromptInterface* GetInstance();
+  static void SetInstance(ArCoreConsentPromptInterface*);
+  static ArCoreConsentPromptInterface* GetInstance();
 
   virtual void ShowConsentPrompt(
       int render_process_id,
diff --git a/chrome/browser/vr/service/xr_device_impl.cc b/chrome/browser/vr/service/xr_device_impl.cc
index a0052f5..5a464fd 100644
--- a/chrome/browser/vr/service/xr_device_impl.cc
+++ b/chrome/browser/vr/service/xr_device_impl.cc
@@ -205,12 +205,14 @@
 #if BUILDFLAG(ENABLE_ARCORE)
     if (!render_frame_host_) {
       // Reject promise.
-      std::move(callback).Run(nullptr);
+      std::move(callback).Run(
+          device::mojom::RequestSessionResult::NewFailureReason(
+              device::mojom::RequestSessionError::INVALID_CLIENT));
     } else {
       if (IsXrDeviceConsentPromptDisabledForTesting()) {
         DoRequestSession(std::move(options), std::move(callback));
       } else {
-        ArcoreConsentPromptInterface::GetInstance()->ShowConsentPrompt(
+        ArCoreConsentPromptInterface::GetInstance()->ShowConsentPrompt(
             render_frame_host_->GetProcess()->GetID(),
             render_frame_host_->GetRoutingID(),
             base::BindOnce(&XRDeviceImpl::OnConsentResult,
diff --git a/chrome/browser/wake_lock/wake_lock_browsertest.cc b/chrome/browser/wake_lock/wake_lock_browsertest.cc
index 0753014..d75567a 100644
--- a/chrome/browser/wake_lock/wake_lock_browsertest.cc
+++ b/chrome/browser/wake_lock/wake_lock_browsertest.cc
@@ -14,6 +14,8 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 
 namespace {
@@ -49,35 +51,107 @@
   DISALLOW_COPY_AND_ASSIGN(PermissionRequestObserver);
 };
 
+// Handles HTTP requests to |path| with |content| as the response body.
+// |content| is expected to be JavaScript; the response mime type is always set
+// to "text/javascript".
+// Invokes |done_callback| after serving the HTTP request.
+std::unique_ptr<net::test_server::HttpResponse> RespondWithJS(
+    const std::string& path,
+    const std::string& content,
+    base::OnceClosure done_callback,
+    const net::test_server::HttpRequest& request) {
+  GURL request_url = request.GetURL();
+  if (request_url.path() != path)
+    return nullptr;
+
+  auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+  response->set_content_type("text/javascript");
+  response->set_content(content);
+  std::move(done_callback).Run();
+  return response;
+}
+
 }  // namespace
 
 class WakeLockBrowserTest : public InProcessBrowserTest {
  protected:
   // InProcessBrowserTest:
   void SetUpCommandLine(base::CommandLine* command_line) override;
-  void SetUpOnMainThread() override;
+
+  // Shorthand for starting the embedded web server and navigating to
+  // simple.html.
+  // Tests calling this usually call content::ExecuteScriptAndExtractString()
+  // afterwards to run custom code on the dummy page.
+  void NavigateToSimplePage();
+
+  // Registers a handle for "/js-response" in the embedded web server that
+  // responds with |script| as the response body, and then navigates to |path|.
+  // |path| usually points to a page that will somehow make a request to
+  // "/js-response".
+  void NavigateToAndRespondWithScript(const std::string& path,
+                                      const std::string& script);
 };
 
 void WakeLockBrowserTest::SetUpCommandLine(base::CommandLine* command_line) {
   command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures, "WakeLock");
 }
 
-void WakeLockBrowserTest::SetUpOnMainThread() {
-  // Navigate to a secure context.
-  embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
+void WakeLockBrowserTest::NavigateToSimplePage() {
   ASSERT_TRUE(embedded_test_server()->Start());
-  ui_test_utils::NavigateToURL(
-      browser(),
-      embedded_test_server()->GetURL("localhost", "/simple_page.html"));
-  auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_THAT(
-      web_contents->GetMainFrame()->GetLastCommittedOrigin().Serialize(),
-      testing::StartsWith("http://localhost:"));
+  ui_test_utils::NavigateToURL(browser(),
+                               embedded_test_server()->GetURL("/simple.html"));
+}
+
+void WakeLockBrowserTest::NavigateToAndRespondWithScript(
+    const std::string& path,
+    const std::string& script) {
+  base::RunLoop loop;
+  embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+      &RespondWithJS, "/js-response", script, loop.QuitClosure()));
+  ASSERT_TRUE(embedded_test_server()->Start());
+  ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL(path));
+  loop.Run();
+}
+
+// https://w3c.github.io/wake-lock/#request-static-method
+// Screen locks are never allowed from workers.
+IN_PROC_BROWSER_TEST_F(WakeLockBrowserTest, RequestScreenLockFromWorker) {
+  PermissionRequestObserver observer(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  const std::string kWorkerScript =
+      "WakeLock.request('screen').catch(err => self.postMessage(err.name))";
+  NavigateToAndRespondWithScript(
+      "/workers/create_dedicated_worker.html?worker_url=/js-response",
+      kWorkerScript);
+  EXPECT_EQ(
+      "NotAllowedError",
+      content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
+                      "waitForMessage();"));
+  EXPECT_EQ(observer.request_shown(), false);
+}
+
+// Requests for a system lock should always be denied, and there should be no
+// permission prompt.
+IN_PROC_BROWSER_TEST_F(WakeLockBrowserTest, RequestSystemLockFromWorker) {
+  PermissionRequestObserver observer(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  const std::string kWorkerScript =
+      "WakeLock.request('system').catch(err => self.postMessage(err.name))";
+  NavigateToAndRespondWithScript(
+      "/workers/create_dedicated_worker.html?worker_url=/js-response",
+      kWorkerScript);
+  EXPECT_EQ(
+      "NotAllowedError",
+      content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
+                      "waitForMessage();"));
+  EXPECT_EQ(observer.request_shown(), false);
 }
 
 IN_PROC_BROWSER_TEST_F(WakeLockBrowserTest, RequestPermissionScreen) {
   // Requests for a screen lock should always be granted, and there should be no
   // permission prompt.
+  NavigateToSimplePage();
+
   PermissionRequestObserver observer(
       browser()->tab_strip_model()->GetActiveWebContents());
   std::string response;
@@ -94,6 +168,8 @@
                        RequestPermissionScreenNoUserGesture) {
   // Requests for a screen lock should always be granted, and there should be no
   // permission prompt.
+  NavigateToSimplePage();
+
   PermissionRequestObserver observer(
       browser()->tab_strip_model()->GetActiveWebContents());
   std::string response;
@@ -109,6 +185,8 @@
 IN_PROC_BROWSER_TEST_F(WakeLockBrowserTest, RequestPermissionSystem) {
   // Requests for a system lock should always be denied, and there should be no
   // permission prompt.
+  NavigateToSimplePage();
+
   PermissionRequestObserver observer(
       browser()->tab_strip_model()->GetActiveWebContents());
   std::string response;
@@ -125,6 +203,8 @@
                        RequestPermissionSystemNoUserGesture) {
   // Requests for a system lock should always be denied, and there should be no
   // permission prompt.
+  NavigateToSimplePage();
+
   PermissionRequestObserver observer(
       browser()->tab_strip_model()->GetActiveWebContents());
   std::string response;
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index cad27f6..00d0ad6f 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -86,8 +86,8 @@
     "test/test_web_app_database.h",
     "test/test_web_app_database_factory.cc",
     "test/test_web_app_database_factory.h",
-    "test/test_web_app_ui_delegate.cc",
-    "test/test_web_app_ui_delegate.h",
+    "test/test_web_app_ui_manager.cc",
+    "test/test_web_app_ui_manager.h",
     "test/test_web_app_url_loader.cc",
     "test/test_web_app_url_loader.h",
     "test/web_app_test.cc",
diff --git a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc
index 717598a..28b6033 100644
--- a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc
@@ -20,7 +20,7 @@
 #include "chrome/browser/web_applications/test/test_app_registrar.h"
 #include "chrome/browser/web_applications/test/test_pending_app_manager.h"
 #include "chrome/browser/web_applications/test/test_system_web_app_manager.h"
-#include "chrome/browser/web_applications/test/test_web_app_ui_delegate.h"
+#include "chrome/browser/web_applications/test/test_web_app_ui_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
@@ -83,6 +83,10 @@
         std::make_unique<TestSystemWebAppManager>(profile());
     system_web_app_manager_ = system_web_app_manager.get();
     provider->SetSystemWebAppManager(std::move(system_web_app_manager));
+
+    auto ui_manager = std::make_unique<TestWebAppUiManager>();
+    ui_manager_ = ui_manager.get();
+    provider->SetWebAppUiManager(std::move(ui_manager));
   }
 
   void SimulatePreviouslyInstalledApp(
@@ -104,14 +108,14 @@
     return system_web_app_manager_;
   }
 
-  TestWebAppUiDelegate* ui_delegate() { return &ui_delegate_; }
+  TestWebAppUiManager* ui_manager() { return ui_manager_; }
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   TestAppRegistrar* test_app_registrar_ = nullptr;
   TestPendingAppManager* test_pending_app_manager_ = nullptr;
   TestSystemWebAppManager* system_web_app_manager_ = nullptr;
-  TestWebAppUiDelegate ui_delegate_;
+  TestWebAppUiManager* ui_manager_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(SystemWebAppManagerTest);
 };
@@ -127,7 +131,7 @@
   system_apps[SystemAppType::SETTINGS] = {kAppUrl1};
 
   system_web_app_manager()->SetSystemApps(std::move(system_apps));
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
 
   base::RunLoop().RunUntilIdle();
 
@@ -146,7 +150,7 @@
   system_apps[SystemAppType::DISCOVER] = {kAppUrl2};
 
   system_web_app_manager()->SetSystemApps(std::move(system_apps));
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
   base::RunLoop().RunUntilIdle();
 
   const auto& apps_to_install = pending_app_manager()->install_requests();
@@ -164,7 +168,7 @@
   system_apps[SystemAppType::SETTINGS] = {kAppUrl1};
 
   system_web_app_manager()->SetSystemApps(std::move(system_apps));
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
 
   base::RunLoop().RunUntilIdle();
 
@@ -189,7 +193,7 @@
   system_web_app_manager()->SetSystemApps(system_apps);
 
   system_web_app_manager()->set_current_version(base::Version("1.0.0.0"));
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
 
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, pending_app_manager()->install_requests().size());
@@ -198,7 +202,7 @@
   // install.
   system_apps[SystemAppType::DISCOVER] = {kAppUrl2};
   system_web_app_manager()->SetSystemApps(system_apps);
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
 
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(3u, pending_app_manager()->install_requests().size());
@@ -208,14 +212,14 @@
     base::test::ScopedFeatureList disable_feature_list;
     disable_feature_list.InitWithFeatures({}, {features::kSystemWebApps});
 
-    system_web_app_manager()->Start(ui_delegate());
+    system_web_app_manager()->Start();
 
     base::RunLoop().RunUntilIdle();
     EXPECT_EQ(2u, pending_app_manager()->uninstall_requests().size());
   }
 
   // Re-enabling System Web Apps installs without a version change.
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
 
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(5u, pending_app_manager()->install_requests().size());
@@ -233,7 +237,7 @@
   system_web_app_manager()->SetSystemApps(system_apps);
 
   system_web_app_manager()->set_current_version(base::Version("1.0.0.0"));
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, install_requests.size());
@@ -245,7 +249,7 @@
   // force reinstall.
   system_apps[SystemAppType::DISCOVER] = {kAppUrl2};
   system_web_app_manager()->SetSystemApps(system_apps);
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(3u, install_requests.size());
@@ -257,7 +261,7 @@
   // Bump the version number, and an update will trigger, and force
   // reinstallation of both apps.
   system_web_app_manager()->set_current_version(base::Version("2.0.0.0"));
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(5u, install_requests.size());
@@ -271,7 +275,7 @@
     base::test::ScopedFeatureList disable_feature_list;
     disable_feature_list.InitWithFeatures({}, {features::kSystemWebApps});
 
-    system_web_app_manager()->Start(ui_delegate());
+    system_web_app_manager()->Start();
     base::RunLoop().RunUntilIdle();
 
     EXPECT_EQ(2u, pending_app_manager()->uninstall_requests().size());
@@ -280,7 +284,7 @@
   }
 
   // Re-enabling System Web Apps installs even without a version change.
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(7u, install_requests.size());
@@ -293,7 +297,7 @@
   // change.
   system_apps[SystemAppType::SETTINGS] = {kAppUrl3};
   system_web_app_manager()->SetSystemApps(system_apps);
-  system_web_app_manager()->Start(ui_delegate());
+  system_web_app_manager()->Start();
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(9u, install_requests.size());
@@ -313,7 +317,7 @@
 
     histograms.ExpectTotalCount(
         SystemWebAppManager::kInstallResultHistogramName, 0);
-    system_web_app_manager()->Start(ui_delegate());
+    system_web_app_manager()->Start();
     base::RunLoop().RunUntilIdle();
 
     histograms.ExpectTotalCount(
@@ -330,7 +334,7 @@
     pending_app_manager()->SetInstallResultCode(
         InstallResultCode::kInstallManagerDestroyed);
 
-    system_web_app_manager()->Start(ui_delegate());
+    system_web_app_manager()->Start();
     base::RunLoop().RunUntilIdle();
     histograms.ExpectTotalCount(
         SystemWebAppManager::kInstallResultHistogramName, 3);
diff --git a/chrome/browser/web_applications/bookmark_apps/test_web_app_provider.cc b/chrome/browser/web_applications/bookmark_apps/test_web_app_provider.cc
index 276a3b7..431f3cd 100644
--- a/chrome/browser/web_applications/bookmark_apps/test_web_app_provider.cc
+++ b/chrome/browser/web_applications/bookmark_apps/test_web_app_provider.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/web_applications/components/install_manager.h"
 #include "chrome/browser/web_applications/components/pending_app_manager.h"
 #include "chrome/browser/web_applications/components/policy/web_app_policy_manager.h"
+#include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/components/web_app_utils.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/test/test_system_web_app_manager.h"
@@ -56,6 +57,12 @@
   ConnectSubsystems();
 }
 
+void TestWebAppProvider::SetWebAppUiManager(
+    std::unique_ptr<WebAppUiManager> ui_manager) {
+  ui_manager_ = std::move(ui_manager);
+  ConnectSubsystems();
+}
+
 void TestWebAppProvider::SetSystemWebAppManager(
     std::unique_ptr<SystemWebAppManager> system_web_app_manager) {
   system_web_app_manager_ = std::move(system_web_app_manager);
diff --git a/chrome/browser/web_applications/bookmark_apps/test_web_app_provider.h b/chrome/browser/web_applications/bookmark_apps/test_web_app_provider.h
index 72ad9b5..6e9191a 100644
--- a/chrome/browser/web_applications/bookmark_apps/test_web_app_provider.h
+++ b/chrome/browser/web_applications/bookmark_apps/test_web_app_provider.h
@@ -41,6 +41,7 @@
   void SetInstallFinalizer(std::unique_ptr<InstallFinalizer> install_finalizer);
   void SetPendingAppManager(
       std::unique_ptr<PendingAppManager> pending_app_manager);
+  void SetWebAppUiManager(std::unique_ptr<WebAppUiManager> ui_manager);
   void SetSystemWebAppManager(
       std::unique_ptr<SystemWebAppManager> system_web_app_manager);
   void SetWebAppPolicyManager(
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index ff23d59..8925106 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -47,7 +47,7 @@
     "web_app_shortcut_win.h",
     "web_app_tab_helper_base.cc",
     "web_app_tab_helper_base.h",
-    "web_app_ui_delegate.h",
+    "web_app_ui_manager.h",
     "web_app_url_loader.cc",
     "web_app_url_loader.h",
     "web_app_utils.cc",
diff --git a/chrome/browser/web_applications/components/pending_app_manager.cc b/chrome/browser/web_applications/components/pending_app_manager.cc
index c55cb9cc..f5258f4 100644
--- a/chrome/browser/web_applications/components/pending_app_manager.cc
+++ b/chrome/browser/web_applications/components/pending_app_manager.cc
@@ -35,8 +35,10 @@
 PendingAppManager::~PendingAppManager() = default;
 
 void PendingAppManager::SetSubsystems(AppRegistrar* registrar,
+                                      WebAppUiManager* ui_manager,
                                       InstallFinalizer* finalizer) {
   registrar_ = registrar;
+  ui_manager_ = ui_manager;
   finalizer_ = finalizer;
 }
 
diff --git a/chrome/browser/web_applications/components/pending_app_manager.h b/chrome/browser/web_applications/components/pending_app_manager.h
index 3b6e412..3e52999 100644
--- a/chrome/browser/web_applications/components/pending_app_manager.h
+++ b/chrome/browser/web_applications/components/pending_app_manager.h
@@ -25,6 +25,7 @@
 
 class AppRegistrar;
 class InstallFinalizer;
+class WebAppUiManager;
 
 // PendingAppManager installs, uninstalls, and updates apps.
 //
@@ -48,7 +49,9 @@
   PendingAppManager();
   virtual ~PendingAppManager();
 
-  void SetSubsystems(AppRegistrar* registrar, InstallFinalizer* finalizer);
+  void SetSubsystems(AppRegistrar* registrar,
+                     WebAppUiManager* ui_manager,
+                     InstallFinalizer* finalizer);
 
   virtual void Shutdown() = 0;
 
@@ -99,6 +102,7 @@
 
  protected:
   AppRegistrar* registrar() { return registrar_; }
+  WebAppUiManager* ui_manager() { return ui_manager_; }
   InstallFinalizer* finalizer() { return finalizer_; }
 
  private:
@@ -127,6 +131,7 @@
   void OnAppSynchronized(InstallSource source, const GURL& app_url);
 
   AppRegistrar* registrar_ = nullptr;
+  WebAppUiManager* ui_manager_ = nullptr;
   InstallFinalizer* finalizer_ = nullptr;
 
   base::flat_map<InstallSource, SynchronizeRequest> synchronize_requests_;
diff --git a/chrome/browser/web_applications/components/web_app_provider_base.h b/chrome/browser/web_applications/components/web_app_provider_base.h
index 7a8f45d8..9f4d003 100644
--- a/chrome/browser/web_applications/components/web_app_provider_base.h
+++ b/chrome/browser/web_applications/components/web_app_provider_base.h
@@ -17,7 +17,7 @@
 class InstallManager;
 class AppRegistrar;
 class WebAppPolicyManager;
-class WebAppUiDelegate;
+class WebAppUiManager;
 
 class WebAppProviderBase : public KeyedService {
  public:
@@ -39,7 +39,7 @@
   // present. It's currently only present for Bookmark Apps.
   virtual WebAppPolicyManager* policy_manager() = 0;
 
-  virtual WebAppUiDelegate& ui_delegate() = 0;
+  virtual WebAppUiManager& ui_manager() = 0;
 
   DISALLOW_COPY_AND_ASSIGN(WebAppProviderBase);
 };
diff --git a/chrome/browser/web_applications/components/web_app_ui_delegate.h b/chrome/browser/web_applications/components/web_app_ui_manager.h
similarity index 69%
rename from chrome/browser/web_applications/components/web_app_ui_delegate.h
rename to chrome/browser/web_applications/components/web_app_ui_manager.h
index 4eb84b3..ea27722 100644
--- a/chrome/browser/web_applications/components/web_app_ui_delegate.h
+++ b/chrome/browser/web_applications/components/web_app_ui_manager.h
@@ -2,18 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_UI_DELEGATE_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_UI_DELEGATE_H_
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_UI_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_UI_MANAGER_H_
 
 #include "base/callback_forward.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 
+class Profile;
+
 namespace web_app {
 
+class WebAppDialogManager;
+
 // Pure virtual interface used to perform Web App UI operations or listen to Web
 // App UI events.
-class WebAppUiDelegate {
+class WebAppUiManager {
  public:
+  static std::unique_ptr<WebAppUiManager> Create(Profile* profile);
+
+  virtual ~WebAppUiManager() = default;
+
+  virtual WebAppDialogManager& dialog_manager() = 0;
+
   virtual size_t GetNumWindowsForApp(const AppId& app_id) = 0;
 
   virtual void NotifyOnAllAppWindowsClosed(const AppId& app_id,
@@ -26,4 +36,4 @@
 
 }  // namespace web_app
 
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_UI_DELEGATE_H_
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_UI_MANAGER_H_
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
index 8b2ea4e..88452b6 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
@@ -15,8 +15,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
-#include "chrome/browser/web_applications/components/web_app_provider_base.h"
-#include "chrome/browser/web_applications/components/web_app_ui_delegate.h"
+#include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h"
 #include "content/public/browser/web_contents.h"
 
@@ -112,10 +111,6 @@
   url_loader_ = std::move(url_loader);
 }
 
-web_app::WebAppUiDelegate& PendingBookmarkAppManager::GetUiDelegate() {
-  return web_app::WebAppProviderBase::GetProviderBase(profile_)->ui_delegate();
-}
-
 void PendingBookmarkAppManager::MaybeStartNextInstallation() {
   if (current_task_and_callback_)
     return;
@@ -145,8 +140,8 @@
 
     if (registrar()->IsInstalled(app_id.value())) {
       if (install_options.wait_for_windows_closed &&
-          GetUiDelegate().GetNumWindowsForApp(app_id.value()) != 0) {
-        GetUiDelegate().NotifyOnAllAppWindowsClosed(
+          ui_manager()->GetNumWindowsForApp(app_id.value()) != 0) {
+        ui_manager()->NotifyOnAllAppWindowsClosed(
             app_id.value(),
             base::BindOnce(&PendingBookmarkAppManager::Install,
                            weak_ptr_factory_.GetWeakPtr(), install_options,
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
index 9e28954..dcac748 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
@@ -30,7 +30,7 @@
 namespace web_app {
 class AppRegistrar;
 class InstallFinalizer;
-class WebAppUiDelegate;
+class WebAppUiManager;
 }  // namespace web_app
 
 namespace extensions {
@@ -70,7 +70,7 @@
  private:
   struct TaskAndCallback;
 
-  web_app::WebAppUiDelegate& GetUiDelegate();
+  web_app::WebAppUiManager& GetUiManager();
 
   void MaybeStartNextInstallation();
 
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
index 4ad1639..0e77f0a8 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
@@ -25,7 +25,7 @@
 #include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
 #include "chrome/browser/web_applications/test/test_app_registrar.h"
 #include "chrome/browser/web_applications/test/test_install_finalizer.h"
-#include "chrome/browser/web_applications/test/test_web_app_ui_delegate.h"
+#include "chrome/browser/web_applications/test/test_web_app_ui_manager.h"
 #include "chrome/browser/web_applications/test/test_web_app_url_loader.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -185,12 +185,9 @@
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
     registrar_ = std::make_unique<web_app::TestAppRegistrar>();
-    ui_delegate_ = std::make_unique<web_app::TestWebAppUiDelegate>();
+    ui_manager_ = std::make_unique<web_app::TestWebAppUiManager>();
     install_finalizer_ = std::make_unique<web_app::TestInstallFinalizer>();
     task_factory_ = std::make_unique<TestBookmarkAppInstallationTaskFactory>();
-
-    web_app::WebAppProvider::Get(profile())->set_ui_delegate(
-        ui_delegate_.get());
   }
 
   void TearDown() override {
@@ -262,7 +259,8 @@
   std::unique_ptr<PendingBookmarkAppManager>
   GetPendingBookmarkAppManagerWithTestMocks() {
     auto manager = std::make_unique<PendingBookmarkAppManager>(profile());
-    manager->SetSubsystems(registrar_.get(), install_finalizer_.get());
+    manager->SetSubsystems(registrar_.get(), ui_manager_.get(),
+                           install_finalizer_.get());
     manager->SetTaskFactoryForTesting(base::BindRepeating(
         &TestBookmarkAppInstallationTaskFactory::CreateInstallationTask,
         base::Unretained(task_factory_.get())));
@@ -305,7 +303,7 @@
 
   web_app::TestAppRegistrar* registrar() { return registrar_.get(); }
 
-  web_app::TestWebAppUiDelegate* ui_delegate() { return ui_delegate_.get(); }
+  web_app::TestWebAppUiManager* ui_manager() { return ui_manager_.get(); }
 
   web_app::TestWebAppUrlLoader* url_loader() { return url_loader_; }
 
@@ -316,7 +314,7 @@
  private:
   std::unique_ptr<TestBookmarkAppInstallationTaskFactory> task_factory_;
   std::unique_ptr<web_app::TestAppRegistrar> registrar_;
-  std::unique_ptr<web_app::TestWebAppUiDelegate> ui_delegate_;
+  std::unique_ptr<web_app::TestWebAppUiManager> ui_manager_;
   std::unique_ptr<web_app::TestInstallFinalizer> install_finalizer_;
 
   web_app::TestWebAppUrlLoader* url_loader_ = nullptr;
@@ -1284,7 +1282,7 @@
     install_options.wait_for_windows_closed = true;
     task_factory()->SetNextInstallationTaskResult(
         kFooWebAppUrl, web_app::InstallResultCode::kSuccess);
-    ui_delegate()->SetNumWindowsForApp(GenerateFakeAppId(kFooWebAppUrl), 0);
+    ui_manager()->SetNumWindowsForApp(GenerateFakeAppId(kFooWebAppUrl), 0);
     url_loader()->SetNextLoadUrlResult(
         kFooWebAppUrl, web_app::WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -1327,7 +1325,7 @@
     install_options.wait_for_windows_closed = true;
     task_factory()->SetNextInstallationTaskResult(
         kFooWebAppUrl, web_app::InstallResultCode::kSuccess);
-    ui_delegate()->SetNumWindowsForApp(GenerateFakeAppId(kFooWebAppUrl), 1);
+    ui_manager()->SetNumWindowsForApp(GenerateFakeAppId(kFooWebAppUrl), 1);
     url_loader()->SetNextLoadUrlResult(
         kFooWebAppUrl, web_app::WebAppUrlLoader::Result::kUrlLoaded);
     install_finalizer()->SetNextUninstallExternalWebAppResult(kFooWebAppUrl,
diff --git a/chrome/browser/web_applications/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_app_manager.cc
index cec9fc8..a908c5d 100644
--- a/chrome/browser/web_applications/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/system_web_app_manager.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_install_utils.h"
-#include "chrome/browser/web_applications/components/web_app_ui_delegate.h"
+#include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
@@ -98,14 +98,14 @@
 SystemWebAppManager::~SystemWebAppManager() = default;
 
 void SystemWebAppManager::SetSubsystems(PendingAppManager* pending_app_manager,
-                                        AppRegistrar* registrar) {
+                                        AppRegistrar* registrar,
+                                        WebAppUiManager* ui_manager) {
   pending_app_manager_ = pending_app_manager;
   registrar_ = registrar;
+  ui_manager_ = ui_manager;
 }
 
-void SystemWebAppManager::Start(WebAppUiDelegate* ui_delegate) {
-  ui_delegate_ = ui_delegate;
-
+void SystemWebAppManager::Start() {
   std::map<AppId, GURL> installed_apps =
       registrar_->GetExternallyInstalledApps(InstallSource::kSystemInstalled);
 
@@ -138,7 +138,7 @@
 void SystemWebAppManager::InstallSystemAppsForTesting() {
   on_apps_synchronized_.reset(new base::OneShotEvent());
   system_app_infos_ = CreateSystemWebApps();
-  Start(ui_delegate_);
+  Start();
 
   // Wait for the System Web Apps to install.
   base::RunLoop run_loop;
@@ -218,7 +218,7 @@
 
 void SystemWebAppManager::MigrateSystemWebApps(
     std::set<SystemAppType> already_installed) {
-  DCHECK(ui_delegate_);
+  DCHECK(ui_manager_);
 
   for (const auto& type_and_info : system_app_infos_) {
     // Migrate if a migration source is specified and the app has been newly
@@ -235,8 +235,8 @@
                    << " could not be found when running migration.";
         continue;
       }
-      ui_delegate_->MigrateOSAttributes(type_and_info.second.migration_source,
-                                        *system_app_id);
+      ui_manager_->MigrateOSAttributes(type_and_info.second.migration_source,
+                                       *system_app_id);
     }
   }
 }
diff --git a/chrome/browser/web_applications/system_web_app_manager.h b/chrome/browser/web_applications/system_web_app_manager.h
index 7c99ae6..015a094 100644
--- a/chrome/browser/web_applications/system_web_app_manager.h
+++ b/chrome/browser/web_applications/system_web_app_manager.h
@@ -31,7 +31,7 @@
 
 namespace web_app {
 
-class WebAppUiDelegate;
+class WebAppUiManager;
 
 // An enum that lists the different System Apps that exist. Can be used to
 // retrieve the App ID from the underlying Web App system.
@@ -68,9 +68,10 @@
   virtual ~SystemWebAppManager();
 
   void SetSubsystems(PendingAppManager* pending_app_manager,
-                     AppRegistrar* registrar);
+                     AppRegistrar* registrar,
+                     WebAppUiManager* ui_manager);
 
-  void Start(WebAppUiDelegate* ui_delegate);
+  void Start();
 
   static bool IsEnabled();
 
@@ -127,7 +128,7 @@
 
   AppRegistrar* registrar_ = nullptr;
 
-  WebAppUiDelegate* ui_delegate_ = nullptr;
+  WebAppUiManager* ui_manager_ = nullptr;
 
   base::WeakPtrFactory<SystemWebAppManager> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/web_applications/test/test_pending_app_manager.cc b/chrome/browser/web_applications/test/test_pending_app_manager.cc
index d0aae4e..440043d 100644
--- a/chrome/browser/web_applications/test/test_pending_app_manager.cc
+++ b/chrome/browser/web_applications/test/test_pending_app_manager.cc
@@ -24,7 +24,7 @@
       deduped_uninstall_count_(0),
       registrar_(registrar) {
   // TODO(crbug.com/973324): Wire this up to a TestInstallFinalizer.
-  SetSubsystems(registrar, nullptr);
+  SetSubsystems(registrar, nullptr, nullptr);
 }
 
 TestPendingAppManager::~TestPendingAppManager() = default;
diff --git a/chrome/browser/web_applications/test/test_web_app_ui_delegate.cc b/chrome/browser/web_applications/test/test_web_app_ui_delegate.cc
deleted file mode 100644
index 2ff9c80..0000000
--- a/chrome/browser/web_applications/test/test_web_app_ui_delegate.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2019 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 "chrome/browser/web_applications/test/test_web_app_ui_delegate.h"
-
-#include <utility>
-
-#include "base/callback.h"
-#include "base/stl_util.h"
-#include "base/test/bind_test_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-
-namespace web_app {
-
-TestWebAppUiDelegate::TestWebAppUiDelegate() = default;
-
-TestWebAppUiDelegate::~TestWebAppUiDelegate() = default;
-
-void TestWebAppUiDelegate::SetNumWindowsForApp(const AppId& app_id,
-                                               size_t num_windows_for_app) {
-  app_id_to_num_windows_map_[app_id] = num_windows_for_app;
-}
-
-size_t TestWebAppUiDelegate::GetNumWindowsForApp(const AppId& app_id) {
-  DCHECK(base::Contains(app_id_to_num_windows_map_, app_id));
-  return app_id_to_num_windows_map_[app_id];
-}
-
-void TestWebAppUiDelegate::NotifyOnAllAppWindowsClosed(
-    const AppId& app_id,
-    base::OnceClosure callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindLambdaForTesting(
-                     [&, app_id, callback = std::move(callback)]() mutable {
-                       app_id_to_num_windows_map_[app_id] = 0;
-                       std::move(callback).Run();
-                     }));
-}
-
-}  // namespace web_app
diff --git a/chrome/browser/web_applications/test/test_web_app_ui_manager.cc b/chrome/browser/web_applications/test/test_web_app_ui_manager.cc
new file mode 100644
index 0000000..cf9016e
--- /dev/null
+++ b/chrome/browser/web_applications/test/test_web_app_ui_manager.cc
@@ -0,0 +1,48 @@
+// Copyright 2019 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 "chrome/browser/web_applications/test/test_web_app_ui_manager.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/stl_util.h"
+#include "base/test/bind_test_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace web_app {
+
+TestWebAppUiManager::TestWebAppUiManager() = default;
+
+TestWebAppUiManager::~TestWebAppUiManager() = default;
+
+WebAppDialogManager& TestWebAppUiManager::dialog_manager() {
+  // TODO(crbug.com/973324): Implement a TestWebAppDialogManager to return here.
+  NOTIMPLEMENTED();
+  static WebAppDialogManager* manager = nullptr;
+  return *manager;
+}
+
+void TestWebAppUiManager::SetNumWindowsForApp(const AppId& app_id,
+                                              size_t num_windows_for_app) {
+  app_id_to_num_windows_map_[app_id] = num_windows_for_app;
+}
+
+size_t TestWebAppUiManager::GetNumWindowsForApp(const AppId& app_id) {
+  DCHECK(base::Contains(app_id_to_num_windows_map_, app_id));
+  return app_id_to_num_windows_map_[app_id];
+}
+
+void TestWebAppUiManager::NotifyOnAllAppWindowsClosed(
+    const AppId& app_id,
+    base::OnceClosure callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindLambdaForTesting(
+                     [&, app_id, callback = std::move(callback)]() mutable {
+                       app_id_to_num_windows_map_[app_id] = 0;
+                       std::move(callback).Run();
+                     }));
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/test/test_web_app_ui_delegate.h b/chrome/browser/web_applications/test/test_web_app_ui_manager.h
similarity index 66%
rename from chrome/browser/web_applications/test/test_web_app_ui_delegate.h
rename to chrome/browser/web_applications/test/test_web_app_ui_manager.h
index ecd44999..360842c 100644
--- a/chrome/browser/web_applications/test/test_web_app_ui_delegate.h
+++ b/chrome/browser/web_applications/test/test_web_app_ui_manager.h
@@ -2,24 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_WEB_APPLICATIONS_TEST_TEST_WEB_APP_UI_DELEGATE_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_TEST_TEST_WEB_APP_UI_DELEGATE_H_
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_TEST_TEST_WEB_APP_UI_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_TEST_TEST_WEB_APP_UI_MANAGER_H_
 
 #include <map>
 
 #include "base/macros.h"
-#include "chrome/browser/web_applications/components/web_app_ui_delegate.h"
+#include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 
 namespace web_app {
 
-class TestWebAppUiDelegate : public WebAppUiDelegate {
+class TestWebAppUiManager : public WebAppUiManager {
  public:
-  TestWebAppUiDelegate();
-  virtual ~TestWebAppUiDelegate();
+  TestWebAppUiManager();
+  ~TestWebAppUiManager() override;
 
   void SetNumWindowsForApp(const AppId& app_id, size_t num_windows_for_app);
 
-  // WebAppUiDelegate
+  // WebAppUiManager:
+  WebAppDialogManager& dialog_manager() override;
   size_t GetNumWindowsForApp(const AppId& app_id) override;
   void NotifyOnAllAppWindowsClosed(const AppId& app_id,
                                    base::OnceClosure callback) override;
@@ -28,9 +29,9 @@
  private:
   std::map<AppId, size_t> app_id_to_num_windows_map_;
 
-  DISALLOW_COPY_AND_ASSIGN(TestWebAppUiDelegate);
+  DISALLOW_COPY_AND_ASSIGN(TestWebAppUiManager);
 };
 
 }  // namespace web_app
 
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_TEST_TEST_WEB_APP_UI_DELEGATE_H_
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_TEST_TEST_WEB_APP_UI_MANAGER_H_
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index bc2d9ebf..9cedf1a 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/web_applications/components/web_app_constants.h"