diff --git a/.gitignore b/.gitignore
index c1b82c6..53bde4d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,7 @@
 .*.sw?
 .DS_Store
 .cipd
+.clang-coverage
 .classpath
 .cproject
 .gdb_history
diff --git a/.vpython b/.vpython
index b3bb6ad..f210f49 100644
--- a/.vpython
+++ b/.vpython
@@ -135,6 +135,38 @@
 >
 
 # Used by:
+#   tools/perf/flakiness_cli
+wheel: <
+  name: "infra/python/wheels/pandas/${vpython_platform}"
+  version: "version:0.23.4"
+  match_tag: <
+    platform: "win32"
+  >
+  match_tag: <
+    platform: "win_amd64"
+  >
+  match_tag: <
+    abi: "cp27mu"
+    platform: "manylinux1_i686"
+  >
+  match_tag: <
+    abi: "cp27mu"
+    platform: "manylinux1_x86_64"
+  >
+  match_tag: <
+    platform: "macosx_10_6_intel"
+  >
+>
+wheel: <
+  name: "infra/python/wheels/pytz-py2_py3"
+  version: "version:2018.4"
+>
+wheel: <
+  name: "infra/python/wheels/python-dateutil-py2_py3"
+  version: "version:2.7.3"
+>
+
+# Used by:
 #   chrome/test/vr/perf/latency/run_latency_test.py
 wheel: <
   name: "infra/python/wheels/peakutils-py2_py3"
diff --git a/AUTHORS b/AUTHORS
index 751d0a4..5123c7e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -21,6 +21,7 @@
 Adam Kallai <kadam@inf.u-szeged.hu>
 Adam Roben <adam@github.com>
 Adam Treat <adam.treat@samsung.com>
+Adam Yi <i@adamyi.com>
 Addanki Gandhi Kishor <kishor.ag@samsung.com>
 Adenilson Cavalcanti <a.cavalcanti@samsung.com>
 Aditya Bhargava <heuristicist@gmail.com>
@@ -518,6 +519,7 @@
 Leung Wing Chung <lwchkg@gmail.com>
 Li Yin <li.yin@intel.com>
 Lidwine Genevet <lgenevet@cisco.com>
+Lin Sun <lin.sun@intel.com>
 Lingyun Cai <lingyun.cai@intel.com>
 Lionel Landwerlin <lionel.g.landwerlin@intel.com>
 Lizhi Fan <lizhi.fan@samsung.com>
@@ -997,6 +999,7 @@
 IBM Inc. <*@*.ibm.com>
 IBM Inc. <*@ibm.com>
 Igalia S.L. <*@igalia.com>
+Imagination Technologies Limited <*@imagination.corp-partner.google.com>
 Impossible Dreams Network <*@impossibledreams.net>
 LG Electronics, Inc. <*@lge.com>
 Loongson Technology Corporation Limited. <*@loongson.cn>
diff --git a/BUILD.gn b/BUILD.gn
index 6c85e57..e4d8f64d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -26,6 +26,7 @@
 import("//v8/gni/v8.gni")
 import("//v8/snapshot_toolchain.gni")
 import("//gpu/vulkan/features.gni")
+import("//testing/test.gni")
 
 if (is_android) {
   import("//build/config/android/config.gni")
@@ -346,7 +347,6 @@
         "//chrome/android:chrome_junit_tests",
         "//chrome/android:chrome_public_apk",
         "//chrome/android:chrome_public_test_apk",
-        "//chrome/android:chrome_sync_shell_test_apk",
         "//chrome/test/chromedriver/test/webview_shell:chromedriver_webview_shell_apk",
         "//content/shell/android:content_shell_test_apk",
         "//third_party/custom_tabs_client:custom_tabs_client_example_apk",
@@ -371,6 +371,15 @@
         [ "//third_party/android_crazy_linker:android_crazy_linker_zip_fuzzer" ]
   }
 
+  if (is_linux || is_chromeos) {
+    # This is only used by ChromeOS, but we want maximal fuzzer coverage, so
+    # run it under linux too.
+    deps += [
+      "//third_party/minizip:minizip_compress_fuzzer",
+      "//third_party/minizip:minizip_uncompress_fuzzer",
+    ]
+  }
+
   if (is_linux || is_android) {
     deps += [
       "//third_party/breakpad:breakpad_unittests",
@@ -925,8 +934,22 @@
   # and is useful for testing with the regular isolate mechanism.
   # To run the full layout test suite you need to use
   # :webkit_layout_tests_exparchive, above, instead.
-  group("webkit_layout_tests") {
-    testonly = true
+  generated_script_test("webkit_layout_tests") {
+    generator_script =
+        "//testing/scripts/generators/gen_run_web_tests_script.py"
+    extra_args = []
+    if (is_debug) {
+      extra_args += [
+        "--build-type",
+        "debug",
+      ]
+    } else {
+      extra_args += [
+        "--build-type",
+        "release",
+      ]
+    }
+
     data_deps = [
       ":layout_test_data_mojo_bindings",
       ":layout_test_data_mojo_bindings_lite",
@@ -1200,6 +1223,7 @@
       "chrome/browser/resources:closure_compile",
       "content/browser/resources:closure_compile",
       "ui/webui/resources:closure_compile",
+      "components/ukm/debug:closure_compile",
     ]
     if (is_chromeos) {
       data_deps += [ "ui/file_manager:closure_compile" ]
diff --git a/DEPS b/DEPS
index 48aed19..b138676 100644
--- a/DEPS
+++ b/DEPS
@@ -112,15 +112,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling sfntly
   # and whatever else without interference from each other.
-  'sfntly_revision': '2804148152d27fa2e6ec97a32bc2d56318e51142',
+  'sfntly_revision': 'b55ff303ea2f9e26702b514cf6a3196a2e3e2974',
   # 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': '763fc966993d712445994e53104c5be42976883b',
+  'skia_revision': '88e15bdaf539b43ff7eaeec882ab9c64df7fe49f',
   # 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': '0ccf17e9a990361055b824b75cde457bf5e490f0',
+  'v8_revision': '31b2546b348e864539ade15897eac971b3c0e402',
   # 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.
@@ -128,7 +128,7 @@
   # 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': '2197dc5290522549f5c9421b48d4eb547f4068e2',
+  'angle_revision': '5d2dfa46c05c8c661304922ce1e1e7d7b045a342',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -136,11 +136,11 @@
   # 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': '847fc0b278f8454f8e04c89163bf840aa903df99',
+  'swiftshader_revision': '4169b31090dbe7d48b3e053c571c12414089bf28',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'f2f7c2a92321a1287798e1b7e708dd3a11243719',
+  'pdfium_revision': 'aab0b516aa87a0d2cb9c0eca27ce2afbe2a30344',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -148,7 +148,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'dd412c428ad7c2a60ae4709dfbad6301e499dcb8',
+  'boringssl_revision': '384d0eaf1930af1ebc47eda751f0c78dfcba1c03',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -168,7 +168,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': 'f56830ed406f90f6f53ee6367f2068a0f27bf90b',
+  'freetype_revision': 'fb0d66d04c4dd8d7f9604af1a6001b2737cb5098',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
@@ -176,11 +176,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'c39d9737dc284e8e6eac39ddfa5db5c453760598',
+  'catapult_revision': '5d5091665700495b0d212cc504fd48530565eecf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
-  'libfuzzer_revision': 'a305a5eb85ed42edc5c965c14f308f576cb245ca',
+  'libfuzzer_revision': '2a53098584c48af50aec3fb51febe5e651489774',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-node-modules
   # and whatever else without interference from each other.
@@ -224,7 +224,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': 'fb996dce752507132c40c255898154cce6c072c5',
+  'spv_tools_revision': '1e9fc1aac1074b4d48c7f48af30ddeb2b768d745',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -240,7 +240,7 @@
   # 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': '61791eae36b8155219f6217b64b28eb4f54e3396',
+  'dawn_revision': '2960ec33667a11bb4445dfe8154aef133c741afe',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -261,13 +261,13 @@
 
 deps = {
   'src/chrome/browser/resources/media_router/extension/src':
-    Var('chromium_git') + '/media_router.git' + '@' + '475baa8b2eb0a7a9dd1c96c9c7a6a8d9035cc8d7',
+    Var('chromium_git') + '/media_router.git' + '@' + '29324b698ccd8920bc81c71d42dadc6310f0ad0f',
 
   'src/android_webview/tools/cts_archive': {
       'packages': [
           {
               'package': 'chromium/android_webview/tools/cts_archive',
-              'version': 'version:1.0',
+              'version': 'version:1.1',
           },
       ],
       'condition': 'checkout_android',
@@ -516,7 +516,7 @@
       'packages': [
           {
        'package': 'chromium/third_party/android_tools_bundletool',
-       'version': 'version:0.6.0-cr0',
+       'version': 'version:0.6.2-cr0',
    },
       ],
       'condition': 'checkout_android',
@@ -646,7 +646,7 @@
     Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'),
 
   'src/third_party/cct_dynamic_module/src': {
-      'url': Var('chromium_git') + '/dynamicmodule' + '@' + 'b89f5147c1fdf1d02850932ecd1ff16b8c0be545',
+      'url': Var('chromium_git') + '/dynamicmodule' + '@' + 'b5a34248be7ff38ef4d7836123f3c796dfb18225',
       'condition': 'checkout_android',
   },
 
@@ -655,7 +655,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '6386fdec9f499e98c799a4aa30609e22541c867a',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '63924982b3fdaf3c313e0052fe0c07dae5e4628a',
       'condition': 'checkout_linux',
   },
 
@@ -670,7 +670,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '46e2b4be31c717db64047079cce5c52cbda197ff',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '693e848cded93bf487a75519e185bc8b73cc1bce',
       'condition': 'checkout_linux',
   },
 
@@ -680,7 +680,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '24bca4e741a98a0f6ed9bdeb64c07816243d2873',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6edb632ff8cdbf65569eb80a9ed8f6d841854a2b',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -715,7 +715,7 @@
   },
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '458e9fd3f8e8c913a739389c65dfaf1f77ee9106',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '81f7d1dd5fa4ff50d9a8cd86e7b76796c056459d',
 
   'src/third_party/flac':
     Var('chromium_git') + '/chromium/deps/flac.git' + '@' + 'af862024c8c8fa0ae07ced05e89013d881b00596',
@@ -821,7 +821,7 @@
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'a9bac57ce6c9d390a52ebaad3259f5fdb871210e',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '42d5027992a0946942839b8821765e1512afbc21',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '45f655f2feb7069a7b9b47d1b1a596807bfd4220',
 
   'src/third_party/icu4j': {
       'packages': [
@@ -868,7 +868,7 @@
     Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'd7ed8e2f3f35ce9a3aafdfdc48745ceab66e7229',
 
   'src/third_party/libaom/source/libaom': {
-    'url': Var('aomedia_git') + '/aom.git' + '@' +  '8f2210a2e54a119bede333e9465997240fc079a9',
+    'url': Var('aomedia_git') + '/aom.git' + '@' +  '35171107616f564a4c18dd75eead6b4393c1f6bd',
     'condition': 'checkout_libaom',
   },
 
@@ -908,7 +908,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'fa0076282e62f649483bde868602aab86448a661',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'c66fe1a8930cf1ad43b38dd7cb88f8ae0139b0b2',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4931ebc0a816458c18a6734e91a4d1b5acd5c56',
@@ -946,7 +946,7 @@
 
   # Minizip library. Used on Chrome OS.
   'src/third_party/minizip/src': {
-      'url': Var('chromium_git') + '/external/github.com/nmoinvaz/minizip' + '@' + '53a657318af1fccc4bac7ed230729302b2391d1d',
+      'url': Var('chromium_git') + '/external/github.com/nmoinvaz/minizip' + '@' + 'c47090678d687742eddc60d07c5430279af416d8',
       'condition': 'checkout_linux',
   },
 
@@ -961,6 +961,11 @@
       'condition': 'checkout_nacl and checkout_win',
   },
 
+  'src/third_party/nasm': {
+      'url': Var('chromium_git') + '/chromium/deps/nasm.git' + '@' +
+      '20920a85609b0608d4c9c80b525196d07183b289'
+  },
+
   'src/third_party/netty-tcnative/src': {
       'url': Var('chromium_git') + '/external/netty-tcnative.git' + '@' + '5b46a8ef4a39c39c576fcdaaf718b585d75df463',
       'condition': 'checkout_android',
@@ -1009,7 +1014,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'e16778c0abc9949736587660bb2c1f71c8506bb3',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '606ed681f4ea01e065a9db72a50184c6470b2eb2',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1065,7 +1070,7 @@
   },
 
   'src/third_party/re2/src':
-    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '9a227bed7a0fde418a94c967ef92d4a1fbe5e47f',
+    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '749d64c35e09849045303c3de4e9955597b75b53',
 
   'src/third_party/r8': {
       'packages': [
@@ -1161,7 +1166,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '0d55c887e92b645f6effe753528323ab2ffd94c2',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '4e93329839463c51d1957682ff47f09773ec9eee',
+    Var('webrtc_git') + '/src.git' + '@' + 'e769ed90c3599a131166d5a61625c1b64318fb91',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1192,7 +1197,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5f0bf6da37059c2c7ea9b65054ada076616a2a2b',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c458532c0628bb1da619aff19c050d3685f258b4',
     'condition': 'checkout_src_internal',
   },
 
@@ -1708,7 +1713,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_play_core',
-              'version': 'version:1.3.0-cr0',
+              'version': 'version:1.3.5-cr0',
           },
       ],
       'condition': 'checkout_android',
@@ -2450,19 +2455,6 @@
                 '-d', 'src/components/zucchini',
     ],
   },
-
-  {
-    # We used to use src as a CIPD root. We moved it to a different directory
-    # in crrev.com/c/930178 but left the clobber here to ensure that that CL
-    # could be reverted safely. This can be safely removed once crbug.com/794764
-    # is resolved.
-    'name': 'Android Clobber Deprecated CIPD Root',
-    'pattern': '.',
-    'condition': 'checkout_android',
-    'action': ['src/build/cipd/clobber_cipd_root.py',
-               '--root', 'src',
-    ],
-  },
   {
     'name': 'Fetch Android AFDO profile',
     'pattern': '.',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index ccfebcf..c0aec6c 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -715,7 +715,7 @@
   ) | set('%s@appspot.gserviceaccount.com' % s for s in ('findit-for-me',)
   ) | set('%s@developer.gserviceaccount.com' % s for s in ('3su6n15k.default',)
   ) | set('%s@chops-service-accounts.iam.gserviceaccount.com' % s
-          for s in ('v8-ci-autoroll-builder',)
+          for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
   ) | set('%s@skia-public.iam.gserviceaccount.com' % s
           for s in ('chromium-autoroll',)
   ) | set('%s@skia-corp.google.com.iam.gserviceaccount.com' % s
@@ -1659,6 +1659,7 @@
                  r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
                  r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
                  r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
+                 r"^webrunner[\\/]browser[\\/]frame_impl.cc$",
                  r"^storage[\\/]browser[\\/]fileapi[\\/]" +
                      r"dump_file_system.cc$",
                  r"^headless[\\/]app[\\/]headless_shell\.cc$"))
@@ -2843,19 +2844,29 @@
   return None
 
 
-def _CheckWatchlistsEntrySyntax(key, value, ast):
+def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
   if not isinstance(key, ast.Str):
     return 'Key at line %d must be a string literal' % key.lineno
   if not isinstance(value, ast.List):
     return 'Value at line %d must be a list' % value.lineno
+  for element in value.elts:
+    if not isinstance(element, ast.Str):
+      return 'Watchlist elements on line %d is not a string' % key.lineno
+    if not email_regex.match(element.s):
+      return ('Watchlist element on line %d doesn\'t look like a valid ' +
+              'email: %s') % (key.lineno, element.s)
   return None
 
 
-def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
+def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
   mismatch_template = (
       'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
       'entry (%s)')
 
+  email_regex = input_api.re.compile(
+      r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
+
+  ast = input_api.ast
   i = 0
   last_key = ''
   while True:
@@ -2875,7 +2886,8 @@
     if result is not None:
       return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
 
-    result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
+    result = _CheckWatchlistsEntrySyntax(
+        w_key, w_dict.values[i], ast, email_regex)
     if result is not None:
       return 'Bad entry in WATCHLISTS dict: %s' % result
 
@@ -2893,7 +2905,8 @@
     i = i + 1
 
 
-def _CheckWATCHLISTSSyntax(expression, ast):
+def _CheckWATCHLISTSSyntax(expression, input_api):
+  ast = input_api.ast
   if not isinstance(expression, ast.Expression):
     return 'WATCHLISTS file must contain a valid expression'
   dictionary = expression.body
@@ -2919,7 +2932,7 @@
         'The second entry of the dict in WATCHLISTS file must be '
         'WATCHLISTS dict')
 
-  return _CheckWATCHLISTSEntries(first_value, second_value, ast)
+  return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
 
 
 def _CheckWATCHLISTS(input_api, output_api):
@@ -2943,7 +2956,7 @@
         return [output_api.PresubmitError(
             'Cannot parse WATCHLISTS file', long_text=repr(e))]
 
-      result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
+      result = _CheckWATCHLISTSSyntax(expression, input_api)
       if result is not None:
         return [output_api.PresubmitError(result)]
       break
diff --git a/WATCHLISTS b/WATCHLISTS
index ed41ae5..6ab7089 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1297,12 +1297,13 @@
                   '|chrome/android/java/src/org/chromium/chrome/browser/offlinepages/'
     },
     'omnibox': {
-      'filepath': 'chrome/browser/autocomplete/|'\
-                  'chrome/browser/ui/location_bar/|'\
-                  'chrome/browser/ui/omnibox/|'\
-                  'chrome/browser/ui/.*/location_bar/|'\
-                  'chrome/browser/ui/.*/omnibox/|'\
-                  'components/omnibox/'
+      'filepath': '^chrome/browser/autocomplete/|'\
+                  '^chrome/browser/resources/omnibox|'\
+                  '^chrome/browser/ui/location_bar/|'\
+                  '^chrome/browser/ui/omnibox/|'\
+                  '^chrome/browser/ui/.*/location_bar/|'\
+                  '^chrome/browser/ui/.*/omnibox/|'\
+                  '^components/omnibox/'
     },
     'optimization_guide': {
       'filepath': 'optimization_guide|'\
@@ -1320,6 +1321,9 @@
         'ui/gl/gl_.*egl.*|'\
         'ui/gl/gl_.*ozone.*'
     },
+    'ozone_scenic': {
+      'filepath': 'ui/ozone/platform/scenic',
+    },
     'page_info' : {
       'filepath': 'chrome/browser/ui/page_info/'\
                   '|chrome/browser/ui/.*/page_info/'\
@@ -1469,8 +1473,7 @@
         'content/browser/browsing_instance',
     },
     'smartlock': {
-      'filepath': 'chrome/browser/apps/platform_apps/api/easy_unlock_private/'\
-                  '|chrome/browser/chromeos/login/easy_unlock/'\
+      'filepath': 'chrome/browser/chromeos/login/easy_unlock/'\
                   '|chrome/browser/resources/easy_unlock/'\
                   '|chromeos/components/proximity_auth/'
     },
@@ -1512,8 +1515,7 @@
                   '|chrome/browser/.*supervised_user',
     },
     'sync': {
-      'filepath': '^chrome/android/sync_shell/'\
-                  '|^chrome/browser/ui/sync/'\
+      'filepath': '^chrome/browser/ui/sync/'\
                   '|^chrome/browser/ui/views/sync/'\
                   '|^chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/'\
                   '|^ios/chrome/browser/sync/'\
@@ -1843,7 +1845,8 @@
                          'rayankans+watch@chromium.org',
                          'nator@chromium.org'],
     'background_sync': ['iclelland+watch@chromium.org',
-                        'peter@chromium.org'],
+                        'peter@chromium.org',
+                        'rayankans+watch@chromium.org'],
     'banners': ['dominickn+watch-banners@chromium.org',
                 'hanxi+watch@chromium.org',
                 'pkotwicz+watch@chromium.org'],
@@ -1880,9 +1883,10 @@
     'blink_bindings': ['blink-reviews-bindings@chromium.org'],
     'blink_bindings_serialization': ['jbroman+watch@chromium.org'],
     'blink_bluetooth': ['mattreynolds+watch@chromium.org',
-                        'ortuno+watch@chromium.org'],
+                        'ortuno+watch@chromium.org',
+                        'odejesush+watch@chromium.org'],
     'blink_canvas': [ 'dongseong.hwang@intel.com',
-                      'fserb@chromium.org'],
+                      'fserb+watch@chromium.org'],
     'blink_client_hints': ['yoav@yoav.ws'],
     'blink_clipboard': ['dcheng@chromium.org'],
     'blink_common': ['jbroman+watch@chromium.org',
@@ -1969,7 +1973,7 @@
                                 'drott+blinkwatch@chromium.org',
                                 'dschulze@chromium.org',
                                 'fmalita+watch@chromium.org',
-                                'fserb@chromium.org',
+                                'fserb+watch@chromium.org',
                                 'pdr+graphicswatchlist@chromium.org',
                                 'schenney@chromium.org'],
     'blink_preloadScanner': ['yoav@yoav.ws'],
@@ -2139,7 +2143,8 @@
     'device_bluetooth': ['mattreynolds+watch@chromium.org',
                          'ortuno+watch@chromium.org'],
     'device_chooser': ['juncai+watch@chromium.org',
-                       'mattreynolds+watch@chromium.org'],
+                       'mattreynolds+watch@chromium.org',
+                       'odejesush+watch@chromium.org'],
     'devtools': ['devtools-reviews@chromium.org',
                  'pfeldman@chromium.org'],
     'dial': ['mfoltz+watch@chromium.org',
@@ -2323,6 +2328,11 @@
     'ozone': ['kalyan.kondapally@intel.com',
               'msisov@igalia.com',
               'ozone-reviews@chromium.org'],
+    'ozone_scenic': ['dworsham@google.com',
+                     'rjkroege@chromium.org',
+                     'sergeyu@chromium.org',
+                     'spang+watch@chromium.org',
+                     'wez@chromium.org'],
     'page_info' : ['raymes+watch@chromium.org'],
     'page_load_metrics' : ['bmcquade+watch@chromium.org',
                            'csharrison+watch@chromium.org',
@@ -2450,7 +2460,8 @@
     'ui_display_win': ['robliao+watch@chromium.org'],
     'ui_resources': ['oshima+watch@chromium.org'],
     'ui_strings': ['srahim+watch@chromium.org'],
-    'usb': ['mattreynolds+watch@chromium.org'],
+    'usb': ['mattreynolds+watch@chromium.org',
+            'odejesush+watch@chromium.org'],
     'vaapi': ['vaapi-reviews@chromium.org'],
     'version_assembly': ['caitkp+watch@chromium.org',
                          'gab+watch@chromium.org'],
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index c7cc010..0c21b9a 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -496,8 +496,8 @@
     "browser/aw_download_manager_delegate.h",
     "browser/aw_feature_list.cc",
     "browser/aw_feature_list.h",
-    "browser/aw_field_trial_creator.cc",
-    "browser/aw_field_trial_creator.h",
+    "browser/aw_feature_list_creator.cc",
+    "browser/aw_feature_list_creator.h",
     "browser/aw_form_database.cc",
     "browser/aw_form_database_service.cc",
     "browser/aw_form_database_service.h",
@@ -551,6 +551,8 @@
     "browser/aw_safe_browsing_whitelist_manager.h",
     "browser/aw_settings.cc",
     "browser/aw_settings.h",
+    "browser/aw_speech_recognition_manager_delegate.cc",
+    "browser/aw_speech_recognition_manager_delegate.h",
     "browser/aw_ssl_host_state_delegate.cc",
     "browser/aw_ssl_host_state_delegate.h",
     "browser/aw_url_checker_delegate_impl.cc",
diff --git a/android_webview/DEPS b/android_webview/DEPS
index a522e4e..0deca74 100644
--- a/android_webview/DEPS
+++ b/android_webview/DEPS
@@ -27,6 +27,7 @@
   "+media/media_buildflags.h",
   "+mojo/public/cpp/bindings",
   "+net",
+  "+services/network/network_service.h",
   "+services/network/public/cpp",
   "+services/preferences/tracked",
   "+services/service_manager/public",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index 0e80ae3..d400175 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -69,5 +69,7 @@
   # Interface required for in-process input event handling.
   "+third_party/blink/public/web/WebCompositorInputHandler.h",
   # For find-in-page
-  "+third_party/blink/public/mojom/frame"
+  "+third_party/blink/public/mojom/frame",
+  # Required for the Web Speech API.
+  "+third_party/blink/public/mojom/speech"
 ]
diff --git a/android_webview/browser/aw_autofill_client.cc b/android_webview/browser/aw_autofill_client.cc
index a9da842..56869279 100644
--- a/android_webview/browser/aw_autofill_client.cc
+++ b/android_webview/browser/aw_autofill_client.cc
@@ -76,6 +76,14 @@
   return nullptr;
 }
 
+autofill::payments::PaymentsClient* AwAutofillClient::GetPaymentsClient() {
+  return nullptr;
+}
+
+autofill::FormDataImporter* AwAutofillClient::GetFormDataImporter() {
+  return nullptr;
+}
+
 autofill::StrikeDatabase* AwAutofillClient::GetStrikeDatabase() {
   return nullptr;
 }
@@ -273,6 +281,12 @@
   NOTIMPLEMENTED();
 }
 
+void AwAutofillClient::ConfirmAccountNameFixFlow(
+    std::unique_ptr<base::DictionaryValue> legal_message,
+    base::OnceCallback<void(const base::string16&)> callback) {
+  NOTIMPLEMENTED();
+}
+
 void AwAutofillClient::ConfirmMigrateLocalCardToCloud(
     std::unique_ptr<base::DictionaryValue> legal_message,
     const std::vector<autofill::MigratableCreditCard>& migratable_credit_cards,
@@ -299,8 +313,16 @@
     const autofill::CreditCard& card,
     std::unique_ptr<base::DictionaryValue> legal_message,
     bool should_request_name_from_user,
+    bool should_request_expiration_date_from_user,
     bool show_prompt,
-    base::OnceCallback<void(const base::string16&)> callback) {
+    UserAcceptedUploadCallback callback) {
+  NOTIMPLEMENTED();
+}
+
+void AwAutofillClient::ShowLocalCardMigrationResults(
+    const base::string16& tip_message,
+    const std::vector<autofill::MigratableCreditCard>&
+        migratable_credit_cards) {
   NOTIMPLEMENTED();
 }
 
diff --git a/android_webview/browser/aw_autofill_client.h b/android_webview/browser/aw_autofill_client.h
index ef7ec7d..29c3809 100644
--- a/android_webview/browser/aw_autofill_client.h
+++ b/android_webview/browser/aw_autofill_client.h
@@ -64,6 +64,8 @@
   PrefService* GetPrefs() override;
   syncer::SyncService* GetSyncService() override;
   identity::IdentityManager* GetIdentityManager() override;
+  autofill::payments::PaymentsClient* GetPaymentsClient() override;
+  autofill::FormDataImporter* GetFormDataImporter() override;
   autofill::StrikeDatabase* GetStrikeDatabase() override;
   ukm::UkmRecorder* GetUkmRecorder() override;
   ukm::SourceId GetUkmSourceId() override;
@@ -77,11 +79,18 @@
   void OnUnmaskVerificationResult(PaymentsRpcResult result) override;
   void ShowLocalCardMigrationDialog(
       base::OnceClosure show_migration_dialog_closure) override;
+  void ConfirmAccountNameFixFlow(
+      std::unique_ptr<base::DictionaryValue> legal_message,
+      base::OnceCallback<void(const base::string16&)> callback) override;
   void ConfirmMigrateLocalCardToCloud(
       std::unique_ptr<base::DictionaryValue> legal_message,
       const std::vector<autofill::MigratableCreditCard>&
           migratable_credit_cards,
       LocalCardMigrationCallback start_migrating_cards_callback) override;
+  void ShowLocalCardMigrationResults(
+      const base::string16& tip_message,
+      const std::vector<autofill::MigratableCreditCard>&
+          migratable_credit_cards) override;
   void ConfirmSaveAutofillProfile(const autofill::AutofillProfile& profile,
                                   base::OnceClosure callback) override;
   void ConfirmSaveCreditCardLocally(const autofill::CreditCard& card,
@@ -91,8 +100,9 @@
       const autofill::CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
       bool should_request_name_from_user,
+      bool should_request_expiration_date_from_user,
       bool show_prompt,
-      base::OnceCallback<void(const base::string16&)> callback) override;
+      UserAcceptedUploadCallback callback) override;
   void ConfirmCreditCardFillAssist(const autofill::CreditCard& card,
                                    const base::Closure& callback) override;
   void LoadRiskData(
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index cb6a5e5..cdb1b4a 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -140,6 +140,9 @@
 void AwBrowserContext::PreMainMessageLoopRun(net::NetLog* net_log) {
   FilePath cache_path = GetCacheDir();
 
+  // TODO(ntfschr): set this to nullptr when the NetworkService is disabled,
+  // once we remove a dependency on url_request_context_getter_
+  // (http://crbug.com/887538).
   url_request_context_getter_ = new AwURLRequestContextGetter(
       cache_path, context_storage_path_.Append(kChannelIDFilename),
       CreateProxyConfigService(), user_pref_service_.get(), net_log);
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc
index 6c5e7db..42e713d 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -10,12 +10,10 @@
 #include <utility>
 
 #include "android_webview/browser/aw_browser_context.h"
-#include "android_webview/browser/aw_browser_policy_connector.h"
 #include "android_webview/browser/aw_browser_terminator.h"
 #include "android_webview/browser/aw_content_browser_client.h"
 #include "android_webview/browser/aw_metrics_service_client.h"
 #include "android_webview/browser/net/aw_network_change_notifier_factory.h"
-#include "android_webview/browser/net/aw_url_request_context_getter.h"
 #include "android_webview/common/aw_descriptors.h"
 #include "android_webview/common/aw_paths.h"
 #include "android_webview/common/aw_resource.h"
@@ -31,22 +29,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_current.h"
 #include "base/path_service.h"
-#include "components/autofill/core/common/autofill_prefs.h"
 #include "components/crash/content/browser/child_exit_observer_android.h"
 #include "components/crash/content/browser/crash_dump_manager_android.h"
 #include "components/heap_profiling/supervisor.h"
-#include "components/metrics/metrics_pref_names.h"
-#include "components/metrics/metrics_service.h"
-#include "components/policy/core/browser/configuration_policy_pref_store.h"
-#include "components/policy/core/browser/url_blacklist_manager.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/prefs/in_memory_pref_store.h"
-#include "components/prefs/json_pref_store.h"
-#include "components/prefs/pref_service_factory.h"
 #include "components/services/heap_profiling/public/cpp/settings.h"
 #include "components/user_prefs/user_prefs.h"
-#include "components/variations/pref_names.h"
-#include "components/variations/service/variations_service.h"
+#include "components/variations/variations_crash_keys.h"
 #include "content/public/browser/android/synchronous_compositor.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -57,85 +45,11 @@
 #include "content/public/common/service_names.mojom.h"
 #include "net/android/network_change_notifier_factory_android.h"
 #include "net/base/network_change_notifier.h"
-#include "services/preferences/tracked/segregated_pref_store.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/layout.h"
 #include "ui/gl/gl_surface.h"
 
-namespace {
-
-// These prefs go in the JsonPrefStore, and will persist across runs. Other
-// prefs go in the InMemoryPrefStore, and will be lost when the process ends.
-const char* const kPersistentPrefsWhitelist[] = {
-    // Random seed value for variation's entropy providers, used to assign
-    // experiment groups.
-    metrics::prefs::kMetricsLowEntropySource,
-    // Used by CachingPermutedEntropyProvider to cache generated values.
-    variations::prefs::kVariationsPermutedEntropyCache,
-};
-
-// Shows notifications which correspond to PersistentPrefStore's reading errors.
-void HandleReadError(PersistentPrefStore::PrefReadError error) {}
-
-base::FilePath GetPrefStorePath() {
-  base::FilePath path;
-  base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
-  path = path.Append(FILE_PATH_LITERAL("pref_store"));
-  return path;
-}
-
-std::unique_ptr<PrefService> CreatePrefService(
-    policy::BrowserPolicyConnectorBase* browser_policy_connector) {
-  auto pref_registry = base::MakeRefCounted<user_prefs::PrefRegistrySyncable>();
-  // We only use the autocomplete feature of Autofill, which is controlled via
-  // the manager_delegate. We don't use the rest of Autofill, which is why it is
-  // hardcoded as disabled here.
-  // TODO(crbug.com/873740): The following also disables autocomplete.
-  // Investigate what the intended behavior is.
-  pref_registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileEnabled,
-                                     false);
-  pref_registry->RegisterBooleanPref(
-      autofill::prefs::kAutofillCreditCardEnabled, false);
-  policy::URLBlacklistManager::RegisterProfilePrefs(pref_registry.get());
-
-  pref_registry->RegisterStringPref(
-      android_webview::prefs::kWebRestrictionsAuthority, std::string());
-
-  android_webview::AwURLRequestContextGetter::RegisterPrefs(
-      pref_registry.get());
-  metrics::MetricsService::RegisterPrefs(pref_registry.get());
-  variations::VariationsService::RegisterPrefs(pref_registry.get());
-  safe_browsing::RegisterProfilePrefs(pref_registry.get());
-
-  PrefServiceFactory pref_service_factory;
-
-  std::set<std::string> persistent_prefs;
-  for (const char* const pref_name : kPersistentPrefsWhitelist)
-    persistent_prefs.insert(pref_name);
-
-  // SegregatedPrefStore may be validated with a MAC (message authentication
-  // code). On Android, the store is protected by app sandboxing, so validation
-  // is unnnecessary. Thus validation_delegate is null.
-  pref_service_factory.set_user_prefs(
-      base::MakeRefCounted<SegregatedPrefStore>(
-          base::MakeRefCounted<InMemoryPrefStore>(),
-          base::MakeRefCounted<JsonPrefStore>(GetPrefStorePath()),
-          persistent_prefs, /*validation_delegate=*/nullptr));
-  pref_service_factory.set_managed_prefs(
-      base::MakeRefCounted<policy::ConfigurationPolicyPrefStore>(
-          browser_policy_connector,
-          browser_policy_connector->GetPolicyService(),
-          browser_policy_connector->GetHandlerList(),
-          policy::POLICY_LEVEL_MANDATORY));
-  pref_service_factory.set_read_error_callback(
-      base::BindRepeating(&HandleReadError));
-
-  return pref_service_factory.Create(pref_registry);
-}
-
-}  // namespace
-
 namespace android_webview {
 
 AwBrowserMainParts::AwBrowserMainParts(AwContentBrowserClient* browser_client)
@@ -195,22 +109,16 @@
         std::make_unique<AwBrowserTerminator>(crash_dir));
   }
 
-  browser_policy_connector_ = std::make_unique<AwBrowserPolicyConnector>();
-  pref_service_ = CreatePrefService(browser_policy_connector_.get());
-  AwMetricsServiceClient::GetInstance()->Initialize(pref_service_.get());
-  aw_field_trial_creator_.SetUpFieldTrials(pref_service_.get());
+  variations::InitCrashKeys();
 
   return service_manager::RESULT_CODE_NORMAL_EXIT;
 }
 
 void AwBrowserMainParts::PreMainMessageLoopRun() {
-  DCHECK(pref_service_);
-  DCHECK(browser_policy_connector_);
-  AwBrowserContext* context = browser_client_->InitBrowserContext(
-      std::move(pref_service_), std::move(browser_policy_connector_));
+  AwBrowserContext* context = browser_client_->InitBrowserContext();
   context->PreMainMessageLoopRun(browser_client_->GetNetLog());
 
-  content::RenderFrameHost::AllowInjectingJavaScriptForAndroidWebView();
+  content::RenderFrameHost::AllowInjectingJavaScript();
 }
 
 bool AwBrowserMainParts::MainMessageLoopRun(int* result_code) {
diff --git a/android_webview/browser/aw_browser_main_parts.h b/android_webview/browser/aw_browser_main_parts.h
index e5eca00..d75fee9 100644
--- a/android_webview/browser/aw_browser_main_parts.h
+++ b/android_webview/browser/aw_browser_main_parts.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "android_webview/browser/aw_field_trial_creator.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "content/public/browser/browser_main_parts.h"
@@ -16,10 +15,6 @@
 class MessageLoop;
 }
 
-namespace policy {
-class BrowserPolicyConnectorBase;
-}
-
 namespace android_webview {
 
 class AwContentBrowserClient;
@@ -41,18 +36,8 @@
   // Android specific UI MessageLoop.
   std::unique_ptr<base::MessageLoop> main_message_loop_;
 
-  // Created and temporarily owned by AwBrowserMainParts
-  // until ownership is transferred to AwBrowserContext.
-  std::unique_ptr<PrefService> pref_service_;
-  std::unique_ptr<policy::BrowserPolicyConnectorBase> browser_policy_connector_;
-
   AwContentBrowserClient* browser_client_;
 
-  // Responsible for creating a feature list from the seed. This object must
-  // exist for the lifetime of the process as it contains the FieldTrialList
-  // that can be queried for the state of experiments.
-  AwFieldTrialCreator aw_field_trial_creator_;
-
   DISALLOW_COPY_AND_ASSIGN(AwBrowserMainParts);
 };
 
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index cad572a..16efdcf 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -15,16 +15,19 @@
 #include "android_webview/browser/aw_contents_io_thread_client.h"
 #include "android_webview/browser/aw_cookie_access_policy.h"
 #include "android_webview/browser/aw_devtools_manager_delegate.h"
+#include "android_webview/browser/aw_feature_list_creator.h"
 #include "android_webview/browser/aw_login_delegate.h"
 #include "android_webview/browser/aw_printing_message_filter.h"
 #include "android_webview/browser/aw_proxying_url_loader_factory.h"
 #include "android_webview/browser/aw_quota_permission_context.h"
 #include "android_webview/browser/aw_settings.h"
+#include "android_webview/browser/aw_speech_recognition_manager_delegate.h"
 #include "android_webview/browser/aw_url_checker_delegate_impl.h"
 #include "android_webview/browser/aw_web_contents_view_delegate.h"
 #include "android_webview/browser/net/aw_url_request_context_getter.h"
 #include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h"
 #include "android_webview/browser/tracing/aw_tracing_delegate.h"
+#include "android_webview/common/aw_content_client.h"
 #include "android_webview/common/aw_descriptors.h"
 #include "android_webview/common/aw_switches.h"
 #include "android_webview/common/crash_reporter/aw_crash_reporter_client.h"
@@ -50,6 +53,7 @@
 #include "components/navigation_interception/intercept_navigation_delegate.h"
 #include "components/policy/content/policy_blacklist_navigation_throttle.h"
 #include "components/policy/core/browser/browser_policy_connector_base.h"
+#include "components/prefs/pref_service.h"
 #include "components/safe_browsing/browser/browser_url_loader_throttle.h"
 #include "components/safe_browsing/browser/mojo_safe_browsing_impl.h"
 #include "components/safe_browsing/features.h"
@@ -62,6 +66,7 @@
 #include "content/public/browser/client_certificate_delegate.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
@@ -76,6 +81,7 @@
 #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"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
@@ -208,7 +214,15 @@
   return AwBrowserContext::GetDefault();
 }
 
-AwContentBrowserClient::AwContentBrowserClient() : net_log_(new net::NetLog()) {
+AwContentBrowserClient::AwContentBrowserClient(
+    AwFeatureListCreator* aw_feature_list_creator)
+    : net_log_(new net::NetLog()),
+      aw_feature_list_creator_(aw_feature_list_creator) {
+  // |aw_feature_list_creator| should not be null. The AwBrowserContext will
+  // take the PrefService owned by the creator as the Local State instead
+  // of loading the JSON file from disk.
+  DCHECK(aw_feature_list_creator_);
+
   // Although WebView does not support password manager feature, renderer code
   // could still request this interface, so we register a dummy binder which
   // just drops the incoming request, to avoid the 'Failed to locate a binder
@@ -220,15 +234,47 @@
 
 AwContentBrowserClient::~AwContentBrowserClient() {}
 
-AwBrowserContext* AwContentBrowserClient::InitBrowserContext(
-    std::unique_ptr<PrefService> pref_service,
-    std::unique_ptr<policy::BrowserPolicyConnectorBase> policy_connector) {
+network::mojom::NetworkContextPtr AwContentBrowserClient::CreateNetworkContext(
+    content::BrowserContext* context,
+    bool in_memory,
+    const base::FilePath& relative_partition_path) {
+  DCHECK(context);
+  if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
+    return nullptr;
+
+  network::mojom::NetworkContextPtr network_context;
+  network::mojom::NetworkContextParamsPtr context_params =
+      network::mojom::NetworkContextParams::New();
+  context_params->user_agent = GetUserAgent();
+  // TODO(ntfschr): set this value to a proper value based on the user's
+  // preferred locales (http://crbug.com/898555). For now, set this to
+  // "en-US,en" instead of "en-us,en", since Android guarantees region codes
+  // will be uppercase.
+  context_params->accept_language = "en-US,en";
+  context_params->enable_data_url_support = true;
+
+  context_params->http_cache_enabled = true;
+  context_params->http_cache_max_size = 20 * 1024 * 1024;  // 20M
+  context_params->http_cache_path = AwBrowserContext::GetCacheDir();
+
+  content::GetNetworkService()->CreateNetworkContext(
+      MakeRequest(&network_context), std::move(context_params));
+
+  // Quic is not currently supported in WebView.
+  content::GetNetworkService()->DisableQuic();
+
+  return network_context;
+}
+
+AwBrowserContext* AwContentBrowserClient::InitBrowserContext() {
   base::FilePath user_data_dir;
   if (!base::PathService::Get(base::DIR_ANDROID_APP_DATA, &user_data_dir)) {
     NOTREACHED() << "Failed to get app data directory for Android WebView";
   }
+
   browser_context_ = std::make_unique<AwBrowserContext>(
-      user_data_dir, std::move(pref_service), std::move(policy_connector));
+      user_data_dir, aw_feature_list_creator_->TakePrefService(),
+      aw_feature_list_creator_->TakeBrowserPolicyConnector());
   return browser_context_.get();
 }
 
@@ -794,6 +840,11 @@
   return true;
 }
 
+content::SpeechRecognitionManagerDelegate*
+AwContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
+  return new AwSpeechRecognitionManagerDelegate();
+}
+
 // static
 void AwContentBrowserClient::DisableCreatingTaskScheduler() {
   g_should_create_task_scheduler = false;
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 1d1a5ee..c7d169b 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -17,8 +17,6 @@
 #include "content/public/browser/content_browser_client.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 
-class PrefService;
-
 namespace content {
 class RenderFrameHost;
 }
@@ -27,10 +25,6 @@
 class NetLog;
 }
 
-namespace policy {
-class BrowserPolicyConnectorBase;
-}
-
 namespace safe_browsing {
 class UrlCheckerDelegate;
 }
@@ -38,6 +32,7 @@
 namespace android_webview {
 
 class AwBrowserContext;
+class AwFeatureListCreator;
 
 class AwContentBrowserClient : public content::ContentBrowserClient {
  public:
@@ -47,14 +42,19 @@
   // Deprecated: use AwBrowserContext::GetDefault() instead.
   static AwBrowserContext* GetAwBrowserContext();
 
-  AwContentBrowserClient();
+  // |aw_feature_list_creator| should not be null.
+  explicit AwContentBrowserClient(
+      AwFeatureListCreator* aw_feature_list_creator);
   ~AwContentBrowserClient() override;
 
   // Allows AwBrowserMainParts to initialize a BrowserContext at the right
   // moment during startup. AwContentBrowserClient owns the result.
-  AwBrowserContext* InitBrowserContext(
-      std::unique_ptr<PrefService> pref_service,
-      std::unique_ptr<policy::BrowserPolicyConnectorBase> policy_connector);
+  AwBrowserContext* InitBrowserContext();
+
+  network::mojom::NetworkContextPtr CreateNetworkContext(
+      content::BrowserContext* context,
+      bool in_memory,
+      const base::FilePath& relative_partition_path) override;
 
   content::BrowserMainParts* CreateBrowserMainParts(
       const content::MainFunctionParams& parameters) override;
@@ -212,6 +212,13 @@
       network::mojom::URLLoaderFactoryRequest* factory_request,
       bool* bypass_redirect_checks) override;
 
+  AwFeatureListCreator* aw_feature_list_creator() {
+    return aw_feature_list_creator_;
+  }
+
+  content::SpeechRecognitionManagerDelegate*
+  CreateSpeechRecognitionManagerDelegate() override;
+
   static void DisableCreatingTaskScheduler();
 
  private:
@@ -231,6 +238,9 @@
 
   bool sniff_file_urls_;
 
+  // The AwFeatureListCreator is owned by AwMainDelegate.
+  AwFeatureListCreator* const aw_feature_list_creator_;
+
   DISALLOW_COPY_AND_ASSIGN(AwContentBrowserClient);
 };
 
diff --git a/android_webview/browser/aw_content_browser_client_unittest.cc b/android_webview/browser/aw_content_browser_client_unittest.cc
index e4e994b..462075e 100644
--- a/android_webview/browser/aw_content_browser_client_unittest.cc
+++ b/android_webview/browser/aw_content_browser_client_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "android_webview/browser/aw_content_browser_client.h"
+#include "android_webview/browser/aw_feature_list_creator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace android_webview {
@@ -10,7 +11,8 @@
 class AwContentBrowserClientTest : public testing::Test {};
 
 TEST_F(AwContentBrowserClientTest, DisableCreatingTaskScheduler) {
-  AwContentBrowserClient client;
+  AwFeatureListCreator aw_feature_list_creator;
+  AwContentBrowserClient client(&aw_feature_list_creator);
   EXPECT_TRUE(client.ShouldCreateTaskScheduler());
 
   AwContentBrowserClient::DisableCreatingTaskScheduler();
diff --git a/android_webview/browser/aw_contents.h b/android_webview/browser/aw_contents.h
index a621d32..5abbceb 100644
--- a/android_webview/browser/aw_contents.h
+++ b/android_webview/browser/aw_contents.h
@@ -27,7 +27,6 @@
 #include "content/public/browser/web_contents_observer.h"
 
 class SkBitmap;
-class TabContents;
 
 namespace autofill {
 class AutofillProvider;
@@ -39,7 +38,6 @@
 
 namespace android_webview {
 
-class AwContentsContainer;
 class AwContentsClientBridge;
 class AwGLFunctor;
 class AwPdfExporter;
@@ -47,9 +45,6 @@
 class PermissionRequestHandler;
 
 // Native side of java-class of same name.
-// Provides the ownership of and access to browser components required for
-// WebView functionality; analogous to chrome's TabContents, but with a
-// level of indirection provided by the AwContentsContainer abstraction.
 //
 // Object lifetime:
 // For most purposes the java and native objects can be considered to have
diff --git a/android_webview/browser/aw_feature_list.cc b/android_webview/browser/aw_feature_list.cc
index 23e1c04..b49f524 100644
--- a/android_webview/browser/aw_feature_list.cc
+++ b/android_webview/browser/aw_feature_list.cc
@@ -47,6 +47,10 @@
 const base::Feature kWebViewConnectionlessSafeBrowsing{
     "WebViewConnectionlessSafeBrowsing", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Whether the application package name is logged in UMA.
+const base::Feature kWebViewUmaLogAppPackageName{
+    "WebViewUmaLogAppPackageName", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 
 static jboolean JNI_AwFeatureList_IsEnabled(
diff --git a/android_webview/browser/aw_feature_list.h b/android_webview/browser/aw_feature_list.h
index def7cff..aaa60eb 100644
--- a/android_webview/browser/aw_feature_list.h
+++ b/android_webview/browser/aw_feature_list.h
@@ -15,6 +15,7 @@
 
 // Alphabetical:
 extern const base::Feature kWebViewConnectionlessSafeBrowsing;
+extern const base::Feature kWebViewUmaLogAppPackageName;
 
 }  // namespace features
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_feature_list_creator.cc b/android_webview/browser/aw_feature_list_creator.cc
new file mode 100644
index 0000000..f479a0e
--- /dev/null
+++ b/android_webview/browser/aw_feature_list_creator.cc
@@ -0,0 +1,177 @@
+// 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.
+
+#include "android_webview/browser/aw_feature_list_creator.h"
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android_webview/browser/aw_browser_context.h"
+#include "android_webview/browser/aw_browser_policy_connector.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"
+#include "base/base_switches.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/path_service.h"
+#include "base/strings/string_split.h"
+#include "base/time/time.h"
+#include "cc/base/switches.h"
+#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/metrics_service.h"
+#include "components/policy/core/browser/configuration_policy_pref_store.h"
+#include "components/policy/core/browser/url_blacklist_manager.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/in_memory_pref_store.h"
+#include "components/prefs/json_pref_store.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/pref_service_factory.h"
+#include "components/variations/entropy_provider.h"
+#include "components/variations/pref_names.h"
+#include "components/variations/service/safe_seed_manager.h"
+#include "components/variations/service/variations_service.h"
+#include "services/preferences/tracked/segregated_pref_store.h"
+
+namespace android_webview {
+
+namespace {
+
+// These prefs go in the JsonPrefStore, and will persist across runs. Other
+// prefs go in the InMemoryPrefStore, and will be lost when the process ends.
+const char* const kPersistentPrefsWhitelist[] = {
+    // Random seed value for variation's entropy providers, used to assign
+    // experiment groups.
+    metrics::prefs::kMetricsLowEntropySource,
+    // Used by CachingPermutedEntropyProvider to cache generated values.
+    variations::prefs::kVariationsPermutedEntropyCache,
+};
+
+// Shows notifications which correspond to PersistentPrefStore's reading errors.
+void HandleReadError(PersistentPrefStore::PrefReadError error) {}
+
+base::FilePath GetPrefStorePath() {
+  base::FilePath path;
+  base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
+  path = path.Append(FILE_PATH_LITERAL("pref_store"));
+  return path;
+}
+
+std::unique_ptr<PrefService> CreatePrefService(
+    policy::BrowserPolicyConnectorBase* browser_policy_connector) {
+  auto pref_registry = base::MakeRefCounted<user_prefs::PrefRegistrySyncable>();
+  // We only use the autocomplete feature of Autofill, which is controlled via
+  // the manager_delegate. We don't use the rest of Autofill, which is why it is
+  // hardcoded as disabled here.
+  // TODO(crbug.com/873740): The following also disables autocomplete.
+  // Investigate what the intended behavior is.
+  pref_registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileEnabled,
+                                     false);
+  pref_registry->RegisterBooleanPref(
+      autofill::prefs::kAutofillCreditCardEnabled, false);
+  policy::URLBlacklistManager::RegisterProfilePrefs(pref_registry.get());
+
+  pref_registry->RegisterStringPref(
+      android_webview::prefs::kWebRestrictionsAuthority, std::string());
+
+  android_webview::AwURLRequestContextGetter::RegisterPrefs(
+      pref_registry.get());
+  metrics::MetricsService::RegisterPrefs(pref_registry.get());
+  variations::VariationsService::RegisterPrefs(pref_registry.get());
+  safe_browsing::RegisterProfilePrefs(pref_registry.get());
+
+  PrefServiceFactory pref_service_factory;
+
+  std::set<std::string> persistent_prefs;
+  for (const char* const pref_name : kPersistentPrefsWhitelist)
+    persistent_prefs.insert(pref_name);
+
+  // SegregatedPrefStore may be validated with a MAC (message authentication
+  // code). On Android, the store is protected by app sandboxing, so validation
+  // is unnnecessary. Thus validation_delegate is null.
+  pref_service_factory.set_user_prefs(base::MakeRefCounted<SegregatedPrefStore>(
+      base::MakeRefCounted<InMemoryPrefStore>(),
+      base::MakeRefCounted<JsonPrefStore>(GetPrefStorePath()), persistent_prefs,
+      /*validation_delegate=*/nullptr));
+  pref_service_factory.set_managed_prefs(
+      base::MakeRefCounted<policy::ConfigurationPolicyPrefStore>(
+          browser_policy_connector,
+          browser_policy_connector->GetPolicyService(),
+          browser_policy_connector->GetHandlerList(),
+          policy::POLICY_LEVEL_MANDATORY));
+  pref_service_factory.set_read_error_callback(
+      base::BindRepeating(&HandleReadError));
+
+  return pref_service_factory.Create(pref_registry);
+}
+
+}  // namespace
+
+AwFeatureListCreator::AwFeatureListCreator()
+    : aw_field_trials_(std::make_unique<AwFieldTrials>()) {}
+
+AwFeatureListCreator::~AwFeatureListCreator() {}
+
+void AwFeatureListCreator::SetUpFieldTrials() {
+  auto* metrics_client = AwMetricsServiceClient::GetInstance();
+
+  // Chrome uses the default entropy provider here (rather than low entropy
+  // provider). The default provider needs to know whether UMA is enabled, but
+  // WebView determines UMA by querying GMS, which is very slow. So WebView
+  // always uses the low entropy provider. Both providers guarantee permanent
+  // consistency, which is the main requirement. The difference is that the low
+  // entropy provider has fewer unique experiment combinations. This is better
+  // for privacy (since experiment state doesn't identify users), but also means
+  // fewer combinations tested in the wild.
+  DCHECK(!field_trial_list_);
+  field_trial_list_ = std::make_unique<base::FieldTrialList>(
+      metrics_client->CreateLowEntropyProvider());
+
+  variations::UIStringOverrider ui_string_overrider;
+  client_ = std::make_unique<AwVariationsServiceClient>();
+  auto seed_store = std::make_unique<variations::VariationsSeedStore>(
+      local_state_.get(), /*initial_seed=*/GetAndClearJavaSeed(),
+      /*on_initial_seed_stored=*/base::DoNothing());
+  variations_field_trial_creator_ =
+      std::make_unique<variations::VariationsFieldTrialCreator>(
+          local_state_.get(), client_.get(), std::move(seed_store),
+          ui_string_overrider);
+  variations_field_trial_creator_->OverrideVariationsPlatform(
+      variations::Study::PLATFORM_ANDROID_WEBVIEW);
+
+  // Unused by WebView, but required by
+  // VariationsFieldTrialCreator::SetupFieldTrials().
+  // TODO(isherman): We might want a more genuine SafeSeedManager:
+  // https://crbug.com/801771
+  std::set<std::string> unforceable_field_trials;
+  variations::SafeSeedManager ignored_safe_seed_manager(true,
+                                                        local_state_.get());
+
+  // Populate FieldTrialList. Since low_entropy_provider is null, it will fall
+  // back to the provider we previously gave to FieldTrialList, which is a low
+  // entropy provider. We only want one low entropy provider, because multiple
+  // CachingPermutedEntropyProvider objects would all try to cache their values
+  // in the same pref store, overwriting each other's.
+  variations_field_trial_creator_->SetupFieldTrials(
+      cc::switches::kEnableGpuBenchmarking, switches::kEnableFeatures,
+      switches::kDisableFeatures, unforceable_field_trials,
+      std::vector<std::string>(), /*low_entropy_provider=*/nullptr,
+      std::make_unique<base::FeatureList>(), aw_field_trials_.get(),
+      &ignored_safe_seed_manager);
+}
+
+void AwFeatureListCreator::CreateFetureListAndFieldTrials() {
+  browser_policy_connector_ = std::make_unique<AwBrowserPolicyConnector>();
+  local_state_ = CreatePrefService(browser_policy_connector_.get());
+  AwMetricsServiceClient::GetInstance()->Initialize(local_state_.get());
+  SetUpFieldTrials();
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/aw_feature_list_creator.h b/android_webview/browser/aw_feature_list_creator.h
new file mode 100644
index 0000000..d0768ef
--- /dev/null
+++ b/android_webview/browser/aw_feature_list_creator.h
@@ -0,0 +1,77 @@
+// 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.
+
+#ifndef ANDROID_WEBVIEW_BROWSER_AW_FEATURE_LIST_CREATOR_H_
+#define ANDROID_WEBVIEW_BROWSER_AW_FEATURE_LIST_CREATOR_H_
+
+#include <memory>
+
+#include "android_webview/browser/aw_field_trials.h"
+#include "android_webview/browser/aw_variations_service_client.h"
+#include "base/metrics/field_trial.h"
+#include "components/policy/core/browser/browser_policy_connector_base.h"
+#include "components/prefs/pref_service.h"
+#include "components/variations/service/variations_field_trial_creator.h"
+
+namespace android_webview {
+
+// Used by WebView to set up field trials based on the stored variations
+// seed data. Once created this object must exist for the lifetime of the
+// process as it contains the FieldTrialList that can be queried for the state
+// of experiments.
+class AwFeatureListCreator {
+ public:
+  AwFeatureListCreator();
+  ~AwFeatureListCreator();
+
+  // Initializes all necessary parameters to create the feature list and setup
+  // field trials.
+  void CreateFetureListAndFieldTrials();
+
+  // Passes ownership of the |local_state_| to the caller.
+  std::unique_ptr<PrefService> TakePrefService() {
+    DCHECK(local_state_);
+    return std::move(local_state_);
+  }
+
+  // Passes ownership of the |browser_policy_connector_| to the caller.
+  std::unique_ptr<policy::BrowserPolicyConnectorBase>
+  TakeBrowserPolicyConnector() {
+    DCHECK(browser_policy_connector_);
+    return std::move(browser_policy_connector_);
+  }
+
+ private:
+  // Sets up the field trials and related initialization.
+  void SetUpFieldTrials();
+
+  // Stores the seed. VariationsSeedStore keeps a raw pointer to this, so it
+  // must persist for the process lifetime. Not persisted accross runs.
+  // If TakePrefService() is called, the caller will take the ownership
+  // of this variable. Stop using this variable afterwards.
+  std::unique_ptr<PrefService> local_state_;
+
+  // A/B testing infrastructure for the entire application. empty until
+  // |SetupFieldTrials()| is called.
+  std::unique_ptr<base::FieldTrialList> field_trial_list_;
+
+  // Performs set up for any WebView specific field trials.
+  std::unique_ptr<AwFieldTrials> aw_field_trials_;
+
+  // Responsible for creating a feature list from the seed.
+  std::unique_ptr<variations::VariationsFieldTrialCreator>
+      variations_field_trial_creator_;
+
+  // If TakePrefService() is called, the caller will take the ownership
+  // of this variable. Stop using this variable afterwards.
+  std::unique_ptr<policy::BrowserPolicyConnectorBase> browser_policy_connector_;
+
+  std::unique_ptr<AwVariationsServiceClient> client_;
+
+  DISALLOW_COPY_AND_ASSIGN(AwFeatureListCreator);
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_AW_FEATURE_LIST_CREATOR_H_
diff --git a/android_webview/browser/aw_field_trial_creator.cc b/android_webview/browser/aw_field_trial_creator.cc
deleted file mode 100644
index a332033..0000000
--- a/android_webview/browser/aw_field_trial_creator.cc
+++ /dev/null
@@ -1,83 +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.
-
-#include "android_webview/browser/aw_field_trial_creator.h"
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "android_webview/browser/aw_metrics_service_client.h"
-#include "android_webview/browser/aw_variations_seed_bridge.h"
-#include "base/base_switches.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/path_service.h"
-#include "base/strings/string_split.h"
-#include "base/time/time.h"
-#include "cc/base/switches.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/pref_service_factory.h"
-#include "components/variations/entropy_provider.h"
-#include "components/variations/service/safe_seed_manager.h"
-
-namespace android_webview {
-
-AwFieldTrialCreator::AwFieldTrialCreator()
-    : aw_field_trials_(std::make_unique<AwFieldTrials>()) {}
-
-AwFieldTrialCreator::~AwFieldTrialCreator() {}
-
-void AwFieldTrialCreator::SetUpFieldTrials(PrefService* pref_service) {
-  auto* metrics_client = AwMetricsServiceClient::GetInstance();
-
-  // Chrome uses the default entropy provider here (rather than low entropy
-  // provider). The default provider needs to know whether UMA is enabled, but
-  // WebView determines UMA by querying GMS, which is very slow. So WebView
-  // always uses the low entropy provider. Both providers guarantee permanent
-  // consistency, which is the main requirement. The difference is that the low
-  // entropy provider has fewer unique experiment combinations. This is better
-  // for privacy (since experiment state doesn't identify users), but also means
-  // fewer combinations tested in the wild.
-  DCHECK(!field_trial_list_);
-  field_trial_list_ = std::make_unique<base::FieldTrialList>(
-      metrics_client->CreateLowEntropyProvider());
-
-  variations::UIStringOverrider ui_string_overrider;
-  client_ = std::make_unique<AwVariationsServiceClient>();
-  auto seed_store = std::make_unique<variations::VariationsSeedStore>(
-      pref_service, /*initial_seed=*/GetAndClearJavaSeed(),
-      /*on_initial_seed_stored=*/base::DoNothing());
-  variations_field_trial_creator_ =
-      std::make_unique<variations::VariationsFieldTrialCreator>(
-          pref_service, client_.get(), std::move(seed_store),
-          ui_string_overrider);
-  variations_field_trial_creator_->OverrideVariationsPlatform(
-      variations::Study::PLATFORM_ANDROID_WEBVIEW);
-
-  // Unused by WebView, but required by
-  // VariationsFieldTrialCreator::SetupFieldTrials().
-  // TODO(isherman): We might want a more genuine SafeSeedManager:
-  // https://crbug.com/801771
-  std::set<std::string> unforceable_field_trials;
-  variations::SafeSeedManager ignored_safe_seed_manager(true, pref_service);
-
-  // Populate FieldTrialList. Since low_entropy_provider is null, it will fall
-  // back to the provider we previously gave to FieldTrialList, which is a low
-  // entropy provider. We only want one low entropy provider, because multiple
-  // CachingPermutedEntropyProvider objects would all try to cache their values
-  // in the same pref store, overwriting each other's.
-  variations_field_trial_creator_->SetupFieldTrials(
-      cc::switches::kEnableGpuBenchmarking, switches::kEnableFeatures,
-      switches::kDisableFeatures, unforceable_field_trials,
-      std::vector<std::string>(), /*low_entropy_provider=*/nullptr,
-      std::make_unique<base::FeatureList>(), aw_field_trials_.get(),
-      &ignored_safe_seed_manager);
-}
-
-}  // namespace android_webview
diff --git a/android_webview/browser/aw_field_trial_creator.h b/android_webview/browser/aw_field_trial_creator.h
deleted file mode 100644
index e49e7ac..0000000
--- a/android_webview/browser/aw_field_trial_creator.h
+++ /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.
-
-#ifndef ANDROID_WEBVIEW_BROWSER_AW_FIELD_TRIAL_CREATOR_H_
-#define ANDROID_WEBVIEW_BROWSER_AW_FIELD_TRIAL_CREATOR_H_
-
-#include <memory>
-
-#include "android_webview/browser/aw_field_trials.h"
-#include "android_webview/browser/aw_variations_service_client.h"
-#include "base/metrics/field_trial.h"
-#include "components/prefs/pref_service.h"
-#include "components/variations/service/variations_field_trial_creator.h"
-
-namespace android_webview {
-
-// Used by WebView to set up field trials based on the stored variations
-// seed data. Once created this object must exist for the lifetime of the
-// process as it contains the FieldTrialList that can be queried for the state
-// of experiments.
-class AwFieldTrialCreator {
- public:
-  AwFieldTrialCreator();
-  ~AwFieldTrialCreator();
-
-  // Sets up the field trials and related initialization.
-  void SetUpFieldTrials(PrefService* pref_service);
-
- private:
-  // Stores the seed. VariationsSeedStore keeps a raw pointer to this, so it
-  // must persist for the process lifetime. Not persisted accross runs.
-  std::unique_ptr<PrefService> local_state_;
-
-  // A/B testing infrastructure for the entire application. empty until
-  // |SetupFieldTrials()| is called.
-  std::unique_ptr<base::FieldTrialList> field_trial_list_;
-
-  // Performs set up for any WebView specific field trials.
-  std::unique_ptr<AwFieldTrials> aw_field_trials_;
-
-  // Responsible for creating a feature list from the seed.
-  std::unique_ptr<variations::VariationsFieldTrialCreator>
-      variations_field_trial_creator_;
-
-  std::unique_ptr<AwVariationsServiceClient> client_;
-
-  DISALLOW_COPY_AND_ASSIGN(AwFieldTrialCreator);
-};
-
-}  // namespace android_webview
-
-#endif  // ANDROID_WEBVIEW_BROWSER_AW_FIELD_TRIAL_CREATOR_H_
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc
index c8c9f91..70d1371 100644
--- a/android_webview/browser/aw_metrics_service_client.cc
+++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 #include <vector>
 
+#include "android_webview/browser/aw_feature_list.h"
 #include "android_webview/browser/aw_metrics_log_uploader.h"
 #include "android_webview/common/aw_switches.h"
 #include "android_webview/jni/AwMetricsServiceClient_jni.h"
@@ -84,8 +85,9 @@
 
 // static
 AwMetricsServiceClient* AwMetricsServiceClient::GetInstance() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  return g_lazy_instance_.Pointer();
+  AwMetricsServiceClient* client = g_lazy_instance_.Pointer();
+  DCHECK(client->sequence_checker_.CalledOnValidSequence());
+  return client;
 }
 
 void AwMetricsServiceClient::LoadOrCreateClientId() {
@@ -134,7 +136,7 @@
 }
 
 void AwMetricsServiceClient::Initialize(PrefService* pref_service) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   DCHECK(pref_service_ == nullptr);  // Initialize should only happen once.
   pref_service_ = pref_service;
@@ -191,7 +193,7 @@
 }
 
 bool AwMetricsServiceClient::IsConsentGiven() const {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return consent_;
 }
 
@@ -200,7 +202,7 @@
 }
 
 void AwMetricsServiceClient::SetHaveMetricsConsent(bool consent) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   consent_ = consent;
   // Receiving this call is the last step in determining whether metrics should
   // be enabled; if so, start metrics. There's no need for a matching Stop()
@@ -267,6 +269,16 @@
   return base::TimeDelta::FromMinutes(kUploadIntervalMinutes);
 }
 
+std::string AwMetricsServiceClient::GetAppPackageName() {
+  if (!base::FeatureList::IsEnabled(features::kWebViewUmaLogAppPackageName))
+    return std::string();
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jstring> j_app_name =
+      Java_AwMetricsServiceClient_getAppPackageName(env);
+  return ConvertJavaStringToUTF8(env, j_app_name);
+}
+
 AwMetricsServiceClient::AwMetricsServiceClient()
     : pref_service_(nullptr),
       consent_(false),
diff --git a/android_webview/browser/aw_metrics_service_client.h b/android_webview/browser/aw_metrics_service_client.h
index 3c420a02..f9a33b4 100644
--- a/android_webview/browser/aw_metrics_service_client.h
+++ b/android_webview/browser/aw_metrics_service_client.h
@@ -11,6 +11,7 @@
 #include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
+#include "base/sequence_checker.h"
 #include "components/metrics/enabled_state_provider.h"
 #include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_service_client.h"
@@ -77,6 +78,7 @@
       const metrics::MetricsLogUploader::UploadCallback& on_upload_complete)
       override;
   base::TimeDelta GetStandardUploadInterval() override;
+  std::string GetAppPackageName() override;
 
  private:
   AwMetricsServiceClient();
@@ -90,6 +92,12 @@
   bool consent_;    // = (user has consented) && !(app has opted out)
   bool in_sample_;  // Is this client enabled by sampling?
 
+  // The AwMetricsServiceClient may be created before the ui thread be promoted
+  // to BrowserThread::UI thread. Therefore, we use |sequence_checker_| to check
+  // whether the AwMetricsServiceClient instance is accessed on the same
+  // thread.
+  base::SequenceChecker sequence_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(AwMetricsServiceClient);
 };
 
diff --git a/android_webview/browser/aw_proxying_url_loader_factory.cc b/android_webview/browser/aw_proxying_url_loader_factory.cc
index 07ca9d2..6829b4e 100644
--- a/android_webview/browser/aw_proxying_url_loader_factory.cc
+++ b/android_webview/browser/aw_proxying_url_loader_factory.cc
@@ -206,14 +206,9 @@
 
     base::PostTaskWithTraits(
         FROM_HERE, {content::BrowserThread::UI},
-        base::BindOnce(
-            &OnReceivedHttpErrorOnUiThread, process_id_,
-            request_.render_frame_id,
-            AwWebResourceRequest(
-                request_.url.spec(), request_.method,
-                request_.resource_type == content::RESOURCE_TYPE_MAIN_FRAME,
-                request_.has_user_gesture, request_.headers),
-            std::move(error_info)));
+        base::BindOnce(&OnReceivedHttpErrorOnUiThread, process_id_,
+                       request_.render_frame_id, AwWebResourceRequest(request_),
+                       std::move(error_info)));
   }
 
   if (request_.resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
@@ -332,20 +327,11 @@
 }
 
 void InterceptedRequest::OnReceivedErrorToCallback(int error_code) {
-  // TODO(timvolodine): add constructor for direct creation from
-  // network::ResourceRequest.
-  AwWebResourceRequest aw_request(
-      request_.url.spec(), request_.method,
-      request_.resource_type == content::RESOURCE_TYPE_MAIN_FRAME,
-      request_.has_user_gesture, request_.headers);
-  // Error callback now requires for |is_renderer_intiated| to be set.
-  aw_request.is_renderer_initiated = ui::PageTransitionIsWebTriggerable(
-      static_cast<ui::PageTransition>(request_.transition_type));
-
-  base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
-                           base::BindOnce(&OnReceivedErrorOnUiThread,
-                                          process_id_, request_.render_frame_id,
-                                          std::move(aw_request), error_code));
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::UI},
+      base::BindOnce(&OnReceivedErrorOnUiThread, process_id_,
+                     request_.render_frame_id, AwWebResourceRequest(request_),
+                     error_code));
 }
 
 }  // namespace
diff --git a/android_webview/browser/aw_settings.cc b/android_webview/browser/aw_settings.cc
index e9aa707..93031b3 100644
--- a/android_webview/browser/aw_settings.cc
+++ b/android_webview/browser/aw_settings.cc
@@ -24,6 +24,7 @@
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/web_preferences.h"
 #include "jni/AwSettings_jni.h"
+#include "net/http/http_util.h"
 #include "services/network/public/cpp/features.h"
 #include "ui/gfx/font_render_params.h"
 
@@ -256,7 +257,7 @@
     content::StoragePartition* storage_partition =
         content::BrowserContext::GetDefaultStoragePartition(aw_browser_context);
     storage_partition->GetNetworkContext()->SetAcceptLanguage(
-        prefs->accept_languages);
+        net::HttpUtil::ExpandLanguageList(prefs->accept_languages));
   }
 }
 
diff --git a/android_webview/browser/aw_speech_recognition_manager_delegate.cc b/android_webview/browser/aw_speech_recognition_manager_delegate.cc
new file mode 100644
index 0000000..b2e0b52
--- /dev/null
+++ b/android_webview/browser/aw_speech_recognition_manager_delegate.cc
@@ -0,0 +1,117 @@
+// 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 "android_webview/browser/aw_speech_recognition_manager_delegate.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/task/post_task.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/speech_recognition_manager.h"
+#include "content/public/browser/speech_recognition_session_context.h"
+#include "content/public/browser/web_contents.h"
+#include "third_party/blink/public/mojom/speech/speech_recognition_error.mojom.h"
+#include "third_party/blink/public/mojom/speech/speech_recognition_result.mojom.h"
+
+using content::BrowserThread;
+
+namespace android_webview {
+
+AwSpeechRecognitionManagerDelegate::AwSpeechRecognitionManagerDelegate() {}
+
+AwSpeechRecognitionManagerDelegate::~AwSpeechRecognitionManagerDelegate() {}
+
+void AwSpeechRecognitionManagerDelegate::OnRecognitionStart(int session_id) {}
+
+void AwSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) {}
+
+void AwSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete(
+    int session_id) {}
+
+void AwSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) {}
+
+void AwSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) {}
+
+void AwSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) {}
+
+void AwSpeechRecognitionManagerDelegate::OnRecognitionResults(
+    int session_id,
+    const std::vector<blink::mojom::SpeechRecognitionResultPtr>& result) {}
+
+void AwSpeechRecognitionManagerDelegate::OnRecognitionError(
+    int session_id,
+    const blink::mojom::SpeechRecognitionError& error) {}
+
+void AwSpeechRecognitionManagerDelegate::OnAudioLevelsChange(
+    int session_id,
+    float volume,
+    float noise_volume) {}
+
+void AwSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) {}
+
+void AwSpeechRecognitionManagerDelegate::CheckRecognitionIsAllowed(
+    int session_id,
+    base::OnceCallback<void(bool ask_user, bool is_allowed)> callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  const content::SpeechRecognitionSessionContext& context =
+      content::SpeechRecognitionManager::GetInstance()->GetSessionContext(
+          session_id);
+
+  // Make sure that initiators (extensions/web pages) properly set the
+  // |render_process_id| field, which is needed later to retrieve the profile.
+  DCHECK_NE(context.render_process_id, 0);
+
+  int render_process_id = context.render_process_id;
+  int render_frame_id = context.render_frame_id;
+  if (context.embedder_render_process_id) {
+    // If this is a request originated from a guest, we need to re-route the
+    // permission check through the embedder (app).
+    render_process_id = context.embedder_render_process_id;
+    render_frame_id = context.embedder_render_frame_id;
+  }
+
+  // Check that the render frame type is appropriate, and whether or not we
+  // need to request permission from the user.
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::UI},
+      base::BindOnce(&CheckRenderFrameType, std::move(callback),
+                     render_process_id, render_frame_id));
+}
+
+content::SpeechRecognitionEventListener*
+AwSpeechRecognitionManagerDelegate::GetEventListener() {
+  return this;
+}
+
+bool AwSpeechRecognitionManagerDelegate::FilterProfanities(
+    int render_process_id) {
+  // TODO: to confirm whether this setting is relevant for android,
+  // https://crbug.com/876801.
+  return false;
+}
+
+// static.
+void AwSpeechRecognitionManagerDelegate::CheckRenderFrameType(
+    base::OnceCallback<void(bool ask_user, bool is_allowed)> callback,
+    int render_process_id,
+    int render_frame_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // Regular tab contents.
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(std::move(callback), true /* check_permission */,
+                     true /* allowed */));
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/aw_speech_recognition_manager_delegate.h b/android_webview/browser/aw_speech_recognition_manager_delegate.h
new file mode 100644
index 0000000..ab39844
--- /dev/null
+++ b/android_webview/browser/aw_speech_recognition_manager_delegate.h
@@ -0,0 +1,66 @@
+// 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 ANDROID_WEBVIEW_BROWSER_AW_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_
+#define ANDROID_WEBVIEW_BROWSER_AW_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "content/public/browser/speech_recognition_event_listener.h"
+#include "content/public/browser/speech_recognition_manager_delegate.h"
+#include "content/public/browser/speech_recognition_session_config.h"
+
+namespace android_webview {
+
+// Android WebView implementation of the SpeechRecognitionManagerDelgate
+// interface.
+class AwSpeechRecognitionManagerDelegate
+    : public content::SpeechRecognitionManagerDelegate,
+      public content::SpeechRecognitionEventListener {
+ public:
+  AwSpeechRecognitionManagerDelegate();
+  ~AwSpeechRecognitionManagerDelegate() override;
+
+ protected:
+  // SpeechRecognitionEventListener methods.
+  void OnRecognitionStart(int session_id) override;
+  void OnAudioStart(int session_id) override;
+  void OnEnvironmentEstimationComplete(int session_id) override;
+  void OnSoundStart(int session_id) override;
+  void OnSoundEnd(int session_id) override;
+  void OnAudioEnd(int session_id) override;
+  void OnRecognitionEnd(int session_id) override;
+  void OnRecognitionResults(
+      int session_id,
+      const std::vector<blink::mojom::SpeechRecognitionResultPtr>& result)
+      override;
+  void OnRecognitionError(
+      int session_id,
+      const blink::mojom::SpeechRecognitionError& error) override;
+  void OnAudioLevelsChange(int session_id,
+                           float volume,
+                           float noise_volume) override;
+
+  // SpeechRecognitionManagerDelegate methods.
+  void CheckRecognitionIsAllowed(
+      int session_id,
+      base::OnceCallback<void(bool ask_user, bool is_allowed)> callback)
+      override;
+  content::SpeechRecognitionEventListener* GetEventListener() override;
+  bool FilterProfanities(int render_process_id) override;
+
+ private:
+  // Checks for VIEW_TYPE_TAB_CONTENTS host in the UI thread and notifies back
+  // the result in the IO thread through |callback|.
+  static void CheckRenderFrameType(
+      base::OnceCallback<void(bool ask_user, bool is_allowed)> callback,
+      int render_process_id,
+      int render_frame_id);
+
+  DISALLOW_COPY_AND_ASSIGN(AwSpeechRecognitionManagerDelegate);
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_AW_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_
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 12b5ec0..6a46c25 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter.cc
@@ -21,6 +21,7 @@
 #include "base/base_paths_android.h"
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
@@ -65,6 +66,7 @@
 #include "net/url_request/url_request_context_builder.h"
 #include "net/url_request/url_request_intercepting_job_factory.h"
 #include "net/url_request/url_request_interceptor.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/network_switches.h"
 
 using base::FilePath;
@@ -306,8 +308,13 @@
                                       std::move(channel_id_service));
 
   net::URLRequestContextBuilder::HttpCacheParams cache_params;
+  // Note: we create this as IN_MEMORY when the network service is enabled
+  // only as a temporary measure, to avoid accessing the same HTTP cache from
+  // two spots in the code.
   cache_params.type =
-      net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
+      base::FeatureList::IsEnabled(network::features::kNetworkService)
+          ? net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY
+          : net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
   cache_params.max_size = 20 * 1024 * 1024;  // 20M
   cache_params.path = cache_path_;
   builder.EnableHttpCache(cache_params);
diff --git a/android_webview/browser/net/aw_web_resource_request.cc b/android_webview/browser/net/aw_web_resource_request.cc
index 0e7fc78..3fbb118 100644
--- a/android_webview/browser/net/aw_web_resource_request.cc
+++ b/android_webview/browser/net/aw_web_resource_request.cc
@@ -8,6 +8,7 @@
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_request.h"
+#include "services/network/public/cpp/resource_request.h"
 #include "ui/base/page_transition_types.h"
 
 using base::android::ConvertJavaStringToUTF16;
@@ -50,6 +51,18 @@
 }
 
 AwWebResourceRequest::AwWebResourceRequest(
+    const network::ResourceRequest& request)
+    : url(request.url.spec()),
+      method(request.method),
+      is_main_frame(request.resource_type == content::RESOURCE_TYPE_MAIN_FRAME),
+      has_user_gesture(request.has_user_gesture),
+      is_renderer_initiated(ui::PageTransitionIsWebTriggerable(
+          static_cast<ui::PageTransition>(request.transition_type))) {
+  ConvertRequestHeadersToVectors(request.headers, &header_names,
+                                 &header_values);
+}
+
+AwWebResourceRequest::AwWebResourceRequest(
     const std::string& in_url,
     const std::string& in_method,
     bool in_is_main_frame,
diff --git a/android_webview/browser/net/aw_web_resource_request.h b/android_webview/browser/net/aw_web_resource_request.h
index 32675bf7..40ac45d 100644
--- a/android_webview/browser/net/aw_web_resource_request.h
+++ b/android_webview/browser/net/aw_web_resource_request.h
@@ -17,6 +17,10 @@
 class URLRequest;
 }
 
+namespace network {
+struct ResourceRequest;
+}
+
 namespace android_webview {
 
 // A passive data structure only used to carry request information. This
@@ -25,6 +29,7 @@
 // https://developer.android.com/reference/android/webkit/WebResourceRequest.html
 struct AwWebResourceRequest final {
   explicit AwWebResourceRequest(const net::URLRequest& request);
+  explicit AwWebResourceRequest(const network::ResourceRequest& request);
   AwWebResourceRequest(const std::string& in_url,
                        const std::string& in_method,
                        bool in_is_main_frame,
diff --git a/android_webview/common/crash_reporter/crash_keys.cc b/android_webview/common/crash_reporter/crash_keys.cc
index 27c245b..e300c40 100644
--- a/android_webview/common/crash_reporter/crash_keys.cc
+++ b/android_webview/common/crash_reporter/crash_keys.cc
@@ -39,6 +39,18 @@
     "mojo-message-error__3",
     "mojo-message-error__4",
     "total-discardable-memory-allocated",
+
+    // crash keys needed for recording finch trials
+    "variations",
+    "variations__1",
+    "variations__2",
+    "variations__3",
+    "variations__4",
+    "variations__5",
+    "variations__6",
+    "variations__7",
+    "variations__8",
+    "num-experiments",
     nullptr};
 // clang-format on
 
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/DrawGLFunctor.java b/android_webview/glue/java/src/com/android/webview/chromium/DrawGLFunctor.java
index 62fdc35..63bda3cd 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/DrawGLFunctor.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/DrawGLFunctor.java
@@ -22,20 +22,20 @@
     private static final String TAG = DrawGLFunctor.class.getSimpleName();
 
     // Pointer to native side instance
-    private final DestroyRunnable mDestroyRunnable;
     private final WebViewDelegate mWebViewDelegate;
+    private long mNativeDrawGLFunctor;
 
     public DrawGLFunctor(long viewContext, WebViewDelegate webViewDelegate) {
-        mDestroyRunnable = new DestroyRunnable(nativeCreateGLFunctor(viewContext));
+        mNativeDrawGLFunctor = nativeCreateGLFunctor(viewContext);
         mWebViewDelegate = webViewDelegate;
     }
 
     @Override
     public void detach(View containerView) {
-        if (mDestroyRunnable.mNativeDrawGLFunctor == 0) {
+        if (mNativeDrawGLFunctor == 0) {
             throw new RuntimeException("detach on already destroyed DrawGLFunctor");
         }
-        mWebViewDelegate.detachDrawGlFunctor(containerView, mDestroyRunnable.mNativeDrawGLFunctor);
+        mWebViewDelegate.detachDrawGlFunctor(containerView, mNativeDrawGLFunctor);
     }
 
     private static final boolean sSupportFunctorReleasedCallback =
@@ -43,24 +43,23 @@
 
     @Override
     public boolean requestDrawGL(Canvas canvas, Runnable releasedCallback) {
-        if (mDestroyRunnable.mNativeDrawGLFunctor == 0) {
+        if (mNativeDrawGLFunctor == 0) {
             throw new RuntimeException("requestDrawGL on already destroyed DrawGLFunctor");
         }
         assert canvas != null;
         if (sSupportFunctorReleasedCallback) {
             assert releasedCallback != null;
-            mWebViewDelegate.callDrawGlFunction(
-                    canvas, mDestroyRunnable.mNativeDrawGLFunctor, releasedCallback);
+            mWebViewDelegate.callDrawGlFunction(canvas, mNativeDrawGLFunctor, releasedCallback);
         } else {
             assert releasedCallback == null;
-            mWebViewDelegate.callDrawGlFunction(canvas, mDestroyRunnable.mNativeDrawGLFunctor);
+            mWebViewDelegate.callDrawGlFunction(canvas, mNativeDrawGLFunctor);
         }
         return true;
     }
 
     @Override
     public boolean requestInvokeGL(View containerView, boolean waitForCompletion) {
-        if (mDestroyRunnable.mNativeDrawGLFunctor == 0) {
+        if (mNativeDrawGLFunctor == 0) {
             throw new RuntimeException("requestInvokeGL on already destroyed DrawGLFunctor");
         }
         if (!sSupportFunctorReleasedCallback
@@ -69,7 +68,7 @@
         }
 
         mWebViewDelegate.invokeDrawGlFunctor(
-                containerView, mDestroyRunnable.mNativeDrawGLFunctor, waitForCompletion);
+                containerView, mNativeDrawGLFunctor, waitForCompletion);
         return true;
     }
 
@@ -79,33 +78,16 @@
     }
 
     @Override
-    public Runnable getDestroyRunnable() {
-        return mDestroyRunnable;
+    public void destroy() {
+        assert mNativeDrawGLFunctor != 0;
+        nativeDestroyGLFunctor(mNativeDrawGLFunctor);
+        mNativeDrawGLFunctor = 0;
     }
 
     public static void setChromiumAwDrawGLFunction(long functionPointer) {
         nativeSetChromiumAwDrawGLFunction(functionPointer);
     }
 
-    // Holds the core resources of the class, everything required to correctly cleanup.
-    // IMPORTANT: this class must not hold any reference back to the outer DrawGLFunctor
-    // instance, as that will defeat GC of that object.
-    private static final class DestroyRunnable implements Runnable {
-        private long mNativeDrawGLFunctor;
-        DestroyRunnable(long nativeDrawGLFunctor) {
-            mNativeDrawGLFunctor = nativeDrawGLFunctor;
-            assert mNativeDrawGLFunctor != 0;
-        }
-
-        // Called when the outer DrawGLFunctor instance has been GC'ed, i.e this is its finalizer.
-        @Override
-        public void run() {
-            assert mNativeDrawGLFunctor != 0;
-            nativeDestroyGLFunctor(mNativeDrawGLFunctor);
-            mNativeDrawGLFunctor = 0;
-        }
-    }
-
     private static native long nativeCreateGLFunctor(long viewContext);
     private static native void nativeDestroyGLFunctor(long functor);
     private static native void nativeSetChromiumAwDrawGLFunction(long functionPointer);
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
index 0b141d6..95c649e 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
@@ -160,7 +160,7 @@
             AwBrowserProcess.configureChildProcessLauncher();
 
             // finishVariationsInitLocked() must precede native initialization so the seed is
-            // available when AwFieldTrialCreator::SetUpFieldTrials() runs.
+            // available when AwFeatureListCreator::SetUpFieldTrials() runs.
             finishVariationsInitLocked();
 
             AwBrowserProcess.start();
@@ -186,7 +186,7 @@
             // library has been loaded and initialized.
             CachedMetrics.commitCachedMetrics();
 
-            RecordHistogram.recordSparseSlowlyHistogram("Android.WebView.TargetSdkVersion",
+            RecordHistogram.recordSparseHistogram("Android.WebView.TargetSdkVersion",
                     context.getApplicationInfo().targetSdkVersion);
 
             try (ScopedSysTraceEvent e = ScopedSysTraceEvent.scoped(
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index d288af8..648039d 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -264,12 +264,10 @@
         void detach(View containerView);
 
         /**
-         * Get a Runnable that is used to destroy the native portion of the functor. After the
-         * run method of this Runnable is called, no other methods should be called on the Java
-         * object.
+         * Destroy this functor instance and any native objects associated with it. No method is
+         * called after destroy.
          */
-        Runnable getDestroyRunnable();
-
+        void destroy();
     }
 
     /**
@@ -306,11 +304,8 @@
 
     private long mNativeAwContents;
     private final AwBrowserContext mBrowserContext;
-    // mContainerView and mCurrentFunctor form a pair that needs to stay in sync.
     private ViewGroup mContainerView;
-    private AwGLFunctor mCurrentFunctor;
-    private AwGLFunctor mInitialFunctor;
-    private AwGLFunctor mFullScreenFunctor; // Only non-null when in fullscreen mode.
+    private AwGLFunctor mDrawFunctor;
     private final Context mContext;
     private final int mAppTargetSdkVersion;
     private AwViewAndroidDelegate mViewAndroidDelegate;
@@ -744,9 +739,8 @@
             ThreadUtils.runOnUiThreadBlocking(() -> {
                 if (isDestroyedOrNoOperation(NO_WARN)) return;
                 if (level >= TRIM_MEMORY_MODERATE) {
-                    mInitialFunctor.deleteHardwareRenderer();
-                    if (mFullScreenFunctor != null) {
-                        mFullScreenFunctor.deleteHardwareRenderer();
+                    if (mDrawFunctor != null) {
+                        mDrawFunctor.deleteHardwareRenderer();
                     }
                 }
                 nativeTrimMemory(mNativeAwContents, level, visible);
@@ -828,8 +822,6 @@
             mAppTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
             mInternalAccessAdapter = internalAccessAdapter;
             mNativeDrawGLFunctorFactory = nativeDrawGLFunctorFactory;
-            mInitialFunctor = new AwGLFunctor(mNativeDrawGLFunctorFactory, mContainerView);
-            mCurrentFunctor = mInitialFunctor;
             mContentsClient = contentsClient;
             mContentsClient.getCallbackHelper().setCancelCallbackPoller(
                     () -> AwContents.this.isDestroyedOrNoOperation(NO_WARN));
@@ -938,13 +930,12 @@
         if (wasInitialContainerViewFocused) {
             fullScreenView.requestFocus();
         }
-        mFullScreenFunctor = new AwGLFunctor(mNativeDrawGLFunctorFactory, fullScreenView);
         mFullScreenTransitionsState.enterFullScreen(fullScreenView, wasInitialContainerViewFocused);
         mAwViewMethods = new NullAwViewMethods(this, mInternalAccessAdapter, mContainerView);
 
         // Associate this AwContents with the FullScreenView.
         setInternalAccessAdapter(fullScreenView.getInternalAccessAdapter());
-        setContainerView(fullScreenView, mFullScreenFunctor);
+        setContainerView(fullScreenView);
 
         return fullScreenView;
     }
@@ -985,15 +976,13 @@
 
         // Re-associate this AwContents with the WebView.
         setInternalAccessAdapter(mFullScreenTransitionsState.getInitialInternalAccessDelegate());
-        setContainerView(initialContainerView, mInitialFunctor);
+        setContainerView(initialContainerView);
 
         // Return focus to the WebView.
         if (mFullScreenTransitionsState.wasInitialContainerViewFocused()) {
             mContainerView.requestFocus();
         }
         mFullScreenTransitionsState.exitFullScreen();
-        // Drop AwContents last reference to this functor. AwGLFunctor is responsible for cleanup.
-        mFullScreenFunctor = null;
     }
 
     private void setInternalAccessAdapter(InternalAccessDelegate internalAccessAdapter) {
@@ -1001,15 +990,15 @@
         mViewEventSink.setAccessDelegate(mInternalAccessAdapter);
     }
 
-    private void setContainerView(ViewGroup newContainerView, AwGLFunctor currentFunctor) {
+    private void setContainerView(ViewGroup newContainerView) {
         // setWillNotDraw(false) is required since WebView draws it's own contents using it's
         // container view. If this is ever not the case we should remove this, as it removes
         // Android's gatherTransparentRegion optimization for the view.
         mContainerView = newContainerView;
-        mCurrentFunctor = currentFunctor;
-        updateNativeAwGLFunctor();
         mContainerView.setWillNotDraw(false);
 
+        assert mDrawFunctor == null;
+
         mViewAndroidDelegate.setContainerView(mContainerView);
         if (mAwPdfExporter != null) {
             mAwPdfExporter.setContainerView(mContainerView);
@@ -1118,9 +1107,18 @@
         }
     }
 
+    private void setFunctor(AwGLFunctor functor) {
+        if (mDrawFunctor == functor) return;
+        AwGLFunctor oldFunctor = mDrawFunctor;
+        mDrawFunctor = functor;
+        updateNativeAwGLFunctor();
+
+        if (oldFunctor != null) oldFunctor.releasedByContents();
+    }
+
     private void updateNativeAwGLFunctor() {
-        nativeSetAwGLFunctor(mNativeAwContents,
-                mCurrentFunctor != null ? mCurrentFunctor.getNativeAwGLFunctor() : 0);
+        nativeSetAwGLFunctor(
+                mNativeAwContents, mDrawFunctor != null ? mDrawFunctor.getNativeAwGLFunctor() : 0);
     }
 
     /* Common initialization routine for adopting a native AwContents instance into this
@@ -1678,9 +1676,6 @@
             String baseUrl, String data, String mimeType, String encoding, String historyUrl) {
         if (TRACE) Log.i(TAG, "%s loadDataWithBaseURL=%s", this, baseUrl);
         if (isDestroyedOrNoOperation(WARN)) return;
-        if (data != null && data.contains("#")) {
-            RecordHistogram.recordBooleanHistogram(DATA_URI_HISTOGRAM_NAME, true);
-        }
 
         data = fixupData(data);
         mimeType = fixupMimeType(mimeType);
@@ -1697,6 +1692,10 @@
         }
 
         if (baseUrl.startsWith("data:")) {
+            // We record only for this branch, because the other branch assumes unencoded content.
+            if (data != null && data.contains("#")) {
+                RecordHistogram.recordBooleanHistogram(DATA_URI_HISTOGRAM_NAME, true);
+            }
             // For backwards compatibility with WebViewClassic, we use the value of |encoding|
             // as the charset, as long as it's not "base64".
             boolean isBase64 = isBase64Encoded(encoding);
@@ -3278,6 +3277,7 @@
         // Only valid within software onDraw().
         private final Rect mClipBoundsTemporary = new Rect();
 
+        @SuppressLint("DrawAllocation") // For new AwGLFunctor.
         @Override
         public void onDraw(Canvas canvas) {
             if (isDestroyedOrNoOperation(NO_WARN)) {
@@ -3293,6 +3293,10 @@
                 return;
             }
 
+            if (canvas.isHardwareAccelerated() && mDrawFunctor == null) {
+                setFunctor(new AwGLFunctor(mNativeDrawGLFunctorFactory, mContainerView));
+            }
+
             mScrollOffsetManager.syncScrollOffsetFromOnDraw();
             int scrollX = mContainerView.getScrollX();
             int scrollY = mContainerView.getScrollY();
@@ -3323,7 +3327,7 @@
             }
             if (did_draw && canvas.isHardwareAccelerated()
                     && !ForceAuxiliaryBitmapRendering.sResult) {
-                did_draw = mCurrentFunctor.requestDrawGL(canvas);
+                did_draw = mDrawFunctor.requestDrawGL(canvas);
             }
             if (did_draw) {
                 int scrollXDiff = mContainerView.getScrollX() - scrollX;
@@ -3487,7 +3491,6 @@
                     mContainerView.getHeight());
             updateHardwareAcceleratedFeaturesToggle();
             postUpdateWebContentsVisibility();
-            mCurrentFunctor.onAttachedToWindow();
 
             updateDefaultLocale();
             mSettings.updateAcceptLanguages();
@@ -3511,7 +3514,7 @@
             mViewEventSink.onDetachedFromWindow();
             updateHardwareAcceleratedFeaturesToggle();
             postUpdateWebContentsVisibility();
-            mCurrentFunctor.onDetachedFromWindow();
+            setFunctor(null);
 
             if (mComponentCallbacks != null) {
                 mContext.unregisterComponentCallbacks(mComponentCallbacks);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwGLFunctor.java b/android_webview/java/src/org/chromium/android_webview/AwGLFunctor.java
index 742fc45..c067cc4 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwGLFunctor.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwGLFunctor.java
@@ -20,26 +20,7 @@
  */
 @JNINamespace("android_webview")
 public class AwGLFunctor {
-    private static final class DestroyRunnable implements Runnable {
-        private final long mNativeAwGLFunctor;
-        private final Runnable mNativeDrawGLFunctorDestroyRunnable;
-
-        private DestroyRunnable(
-                long nativeAwGLFunctor, Runnable nativeDrawGLFunctorDestroyRunnable) {
-            mNativeAwGLFunctor = nativeAwGLFunctor;
-            mNativeDrawGLFunctorDestroyRunnable = nativeDrawGLFunctorDestroyRunnable;
-        }
-        @Override
-        public void run() {
-            mNativeDrawGLFunctorDestroyRunnable.run();
-            nativeDestroy(mNativeAwGLFunctor);
-        }
-    }
-
     private final long mNativeAwGLFunctor;
-    // Same gc-life time as this, but does not reference any members like |mContainerView|.
-    private final Object mLifetimeObject;
-    private final CleanupReference mCleanupReference;
     private final AwContents.NativeDrawGLFunctor mNativeDrawGLFunctor;
     private final ViewGroup mContainerView;
     private final Runnable mFunctorReleasedCallback;
@@ -49,23 +30,19 @@
     public AwGLFunctor(AwContents.NativeDrawGLFunctorFactory nativeDrawGLFunctorFactory,
             ViewGroup containerView) {
         mNativeAwGLFunctor = nativeCreate(this);
-        mNativeDrawGLFunctor = nativeDrawGLFunctorFactory.createFunctor(getAwDrawGLViewContext());
-        mLifetimeObject = new Object();
-        mCleanupReference = new CleanupReference(mLifetimeObject,
-                new DestroyRunnable(mNativeAwGLFunctor, mNativeDrawGLFunctor.getDestroyRunnable()));
+        mNativeDrawGLFunctor = nativeDrawGLFunctorFactory.createFunctor(
+                nativeGetAwDrawGLViewContext(mNativeAwGLFunctor));
         mContainerView = containerView;
         if (mNativeDrawGLFunctor.supportsDrawGLFunctorReleasedCallback()) {
             mFunctorReleasedCallback = () -> removeReference();
         } else {
             mFunctorReleasedCallback = null;
         }
-    }
-
-    public void onAttachedToWindow() {
         addReference();
     }
 
-    public void onDetachedFromWindow() {
+    public void releasedByContents() {
+        assert mRefCount > 0;
         removeReference();
     }
 
@@ -74,10 +51,12 @@
     }
 
     public long getNativeAwGLFunctor() {
+        assert mRefCount > 0;
         return mNativeAwGLFunctor;
     }
 
     public boolean requestDrawGL(Canvas canvas) {
+        assert mRefCount > 0;
         boolean success = mNativeDrawGLFunctor.requestDrawGL(canvas, mFunctorReleasedCallback);
         if (success && mFunctorReleasedCallback != null) {
             addReference();
@@ -90,11 +69,14 @@
     }
 
     private void removeReference() {
+        assert mRefCount > 0;
         if (--mRefCount == 0) {
             // When |mRefCount| decreases to zero, the functor is neither attached to a view, nor
             // referenced from the render tree, and so it is safe to delete the HardwareRenderer
             // instance to free up resources because the current state will not be drawn again.
-            deleteHardwareRenderer();
+            nativeDeleteHardwareRenderer(mNativeAwGLFunctor);
+            mNativeDrawGLFunctor.destroy();
+            nativeDestroy(mNativeAwGLFunctor);
         }
     }
 
@@ -110,13 +92,10 @@
     }
 
     public void deleteHardwareRenderer() {
+        assert mRefCount > 0;
         nativeDeleteHardwareRenderer(mNativeAwGLFunctor);
     }
 
-    public long getAwDrawGLViewContext() {
-        return nativeGetAwDrawGLViewContext(mNativeAwGLFunctor);
-    }
-
     /**
      * Intended for test code.
      * @return the number of native instances of this class.
diff --git a/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java b/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java
index 9dc76aa..4ee4cbf 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java
@@ -8,6 +8,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
@@ -84,5 +85,10 @@
         }
     }
 
+    @CalledByNative
+    private static String getAppPackageName() {
+        return ContextUtils.getApplicationContext().getPackageName();
+    }
+
     public static native void nativeSetHaveMetricsConsent(boolean enabled);
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/VariationsSeedLoader.java b/android_webview/java/src/org/chromium/android_webview/VariationsSeedLoader.java
index ca62674..226ba95 100644
--- a/android_webview/java/src/org/chromium/android_webview/VariationsSeedLoader.java
+++ b/android_webview/java/src/org/chromium/android_webview/VariationsSeedLoader.java
@@ -61,7 +61,7 @@
  * 4. Call finishVariationsInit() with the value returned from startVariationsInit(). This will
  *    block for up to SEED_LOAD_TIMEOUT_MILLIS if the task hasn't fininshed loading the seed. If the
  *    seed is loaded on time, variations will be initialized. finishVariationsInit() must be called
- *    before AwFieldTrialCreator::SetUpFieldTrials() runs.
+ *    before AwFeatureListCreator::SetUpFieldTrials() runs.
  */
 public class VariationsSeedLoader {
     private static final String TAG = "VariationsSeedLoader";
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AcceptLanguageTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AcceptLanguageTest.java
index 8f2f0eba8..35dd11a 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AcceptLanguageTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AcceptLanguageTest.java
@@ -77,8 +77,32 @@
         return COMMA_AND_OPTIONAL_Q_VALUE.split(mActivityTestRule.maybeStripDoubleQuotes(raw));
     }
 
-    private boolean isEnUsLocale() {
-        return "en-US".equals(Locale.getDefault().toLanguageTag());
+    @SuppressLint("NewApi")
+    private boolean isSingleLocale(String lang, String country) {
+        String languageTag = String.format("%s-%s", lang, country);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            // In N+, multiple locales can be set.
+            return languageTag.equals(LocaleList.getDefault().toLanguageTags());
+        } else {
+            return languageTag.equals(Locale.getDefault().toLanguageTag());
+        }
+    }
+
+    @SuppressLint("NewApi")
+    private void setSingleLocale(String lang, String country) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            LocaleList.setDefault(new LocaleList(new Locale(lang, country)));
+        } else {
+            Locale.setDefault(new Locale(lang, country));
+        }
+    }
+
+    private void setLocaleForTesting(String lang, String country) {
+        if (!isSingleLocale(lang, country)) {
+            setSingleLocale(lang, country);
+            AwContents.updateDefaultLocale();
+            mAwContents.getSettings().updateAcceptLanguages();
+        }
     }
 
     /**
@@ -88,13 +112,7 @@
     @SmallTest
     @Feature({"AndroidWebView"})
     public void testAcceptLanguage() throws Throwable {
-        // Make sure that the current locale is en-US.
-        if (!isEnUsLocale()) {
-            Locale.setDefault(new Locale("en", "US"));
-            AwContents.updateDefaultLocale();
-            mAwContents.getSettings().updateAcceptLanguages();
-        }
-        Assert.assertTrue(isEnUsLocale());
+        setLocaleForTesting("en", "US");
 
         mActivityTestRule.getAwSettingsOnUiThread(mAwContents).setJavaScriptEnabled(true);
 
@@ -117,15 +135,14 @@
         Assert.assertArrayEquals(new String[] {"en-US"}, acceptLanguagesJs);
 
         // Test locale change at run time
-        Locale.setDefault(new Locale("de", "DE"));
-        AwContents.updateDefaultLocale();
-        mAwContents.getSettings().updateAcceptLanguages();
+        setLocaleForTesting("de", "DE");
 
         mActivityTestRule.loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
 
         acceptLanguages = getAcceptLanguages(
                 mActivityTestRule.getJavaScriptResultBodyTextContent(mAwContents, mContentsClient));
-        // Note that we extend the base language from language-region pair.
+        // Note that we extend the base language from language-region pair, and we put en-US and en
+        // at the end.
         Assert.assertArrayEquals(new String[] {"de-DE", "de", "en-US", "en"}, acceptLanguages);
     }
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
index 66000c7..cb0bdbc 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
@@ -844,11 +844,19 @@
         });
         Assert.assertEquals(0, getHistogramSampleCount(AwContents.DATA_URI_HISTOGRAM_NAME));
 
-        // Check a URL with a '#' character.
+        // '#' is legal if the baseUrl is not data scheme, because loadDataWithBaseURL accepts
+        // unencoded content.
         mActivityTestRule.runOnUiThread(() -> {
             awContents.loadDataWithBaseURL(
                     "http://www.example.com", "<html>test#foo</html>", "text/html", null, null);
         });
+        Assert.assertEquals(0, getHistogramSampleCount(AwContents.DATA_URI_HISTOGRAM_NAME));
+
+        // Check a URL with a '#' character, with data-scheme baseUrl.
+        mActivityTestRule.runOnUiThread(() -> {
+            awContents.loadDataWithBaseURL(
+                    "data:text/html", "<html>test#foo</html>", "text/html", null, null);
+        });
         Assert.assertEquals(1, getHistogramSampleCount(AwContents.DATA_URI_HISTOGRAM_NAME));
 
         // An encoded '#' should not cause the histogram to increment.
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index b7b3a3d..06275a9 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -321,6 +321,7 @@
   return false;
 }
 
+// This function is called only on the browser process.
 void AwMainDelegate::PostEarlyInitialization(bool is_running_tests) {
   ui::SetLocalePaksStoredInApk(true);
   std::string locale = ui::ResourceBundle::InitSharedInstanceWithLocale(
@@ -338,10 +339,15 @@
   base::PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &pak_file_path);
   pak_file_path = pak_file_path.AppendASCII("resources.pak");
   ui::LoadMainAndroidPackFile("assets/resources.pak", pak_file_path);
+
+  aw_feature_list_creator_->CreateFetureListAndFieldTrials();
 }
 
 content::ContentBrowserClient* AwMainDelegate::CreateContentBrowserClient() {
-  content_browser_client_.reset(new AwContentBrowserClient());
+  DCHECK(!aw_feature_list_creator_);
+  aw_feature_list_creator_ = std::make_unique<AwFeatureListCreator>();
+  content_browser_client_.reset(
+      new AwContentBrowserClient(aw_feature_list_creator_.get()));
   return content_browser_client_.get();
 }
 
diff --git a/android_webview/lib/aw_main_delegate.h b/android_webview/lib/aw_main_delegate.h
index 28b0259..7b7cb08 100644
--- a/android_webview/lib/aw_main_delegate.h
+++ b/android_webview/lib/aw_main_delegate.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "android_webview/browser/aw_feature_list_creator.h"
 #include "android_webview/common/aw_content_client.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -51,6 +52,10 @@
   content::ContentRendererClient* CreateContentRendererClient() override;
   content::ContentUtilityClient* CreateContentUtilityClient() override;
 
+  // Responsible for creating a feature list from the seed. This object must
+  // exist for the lifetime of the process as it contains the FieldTrialList
+  // that can be queried for the state of experiments.
+  std::unique_ptr<AwFeatureListCreator> aw_feature_list_creator_;
   std::unique_ptr<content::BrowserMainRunner> browser_runner_;
   AwContentClient content_client_;
   std::unique_ptr<AwContentBrowserClient> content_browser_client_;
diff --git a/android_webview/support_library/callback/java/src/org/chromium/support_lib_callback_glue/SupportLibWebViewContentsClientAdapter.java b/android_webview/support_library/callback/java/src/org/chromium/support_lib_callback_glue/SupportLibWebViewContentsClientAdapter.java
index 8024a39..566fffe 100644
--- a/android_webview/support_library/callback/java/src/org/chromium/support_lib_callback_glue/SupportLibWebViewContentsClientAdapter.java
+++ b/android_webview/support_library/callback/java/src/org/chromium/support_lib_callback_glue/SupportLibWebViewContentsClientAdapter.java
@@ -14,6 +14,7 @@
 import org.chromium.android_webview.AwSafeBrowsingResponse;
 import org.chromium.android_webview.ScopedSysTraceEvent;
 import org.chromium.base.Callback;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.support_lib_boundary.SafeBrowsingResponseBoundaryInterface;
 import org.chromium.support_lib_boundary.WebResourceErrorBoundaryInterface;
 import org.chromium.support_lib_boundary.WebViewClientBoundaryInterface;
@@ -30,6 +31,9 @@
     private static final String WEBVIEW_CLIENT_COMPAT_NAME = "androidx.webkit.WebViewClientCompat";
     private static final String[] EMPTY_FEATURE_LIST = new String[0];
 
+    private static final String COMPAT_CLIENT_HISTOGRAM =
+            "Android.WebView.SupportLibrary.ClientIsCompat";
+
     // If {@code null}, this indicates the WebViewClient is not a WebViewClientCompat. Otherwise,
     // this is a Proxy for the WebViewClientCompat.
     @Nullable
@@ -47,6 +51,13 @@
             mWebViewClientSupportedFeatures = mWebViewClient == null
                     ? EMPTY_FEATURE_LIST
                     : mWebViewClient.getSupportedFeatures();
+
+            // We ignore the case where the client is set to null, since this is often done by
+            // WebView's internal logic (such as during destroy()), and would otherwise skew data.
+            if (possiblyCompatClient != null) {
+                RecordHistogram.recordBooleanHistogram(
+                        COMPAT_CLIENT_HISTOGRAM, mWebViewClient != null);
+            }
         }
     }
 
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
index f26bbf6..8d79205 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
@@ -443,22 +443,11 @@
         }
     }
 
-    private static final class NativeDrawGLFunctorDestroyRunnable implements Runnable {
-        public long mContext;
-        NativeDrawGLFunctorDestroyRunnable(long context) {
-            mContext = context;
-        }
-        @Override
-        public void run() {
-            mContext = 0;
-        }
-    }
-
     private class NativeDrawGLFunctor implements AwContents.NativeDrawGLFunctor {
-        private NativeDrawGLFunctorDestroyRunnable mDestroyRunnable;
+        private long mContext;
 
         NativeDrawGLFunctor(long context) {
-            mDestroyRunnable = new NativeDrawGLFunctorDestroyRunnable(context);
+            mContext = context;
         }
 
         @Override
@@ -470,14 +459,14 @@
         public boolean requestDrawGL(Canvas canvas, Runnable releasedRunnable) {
             assert releasedRunnable == null;
             if (!isBackedByHardwareView()) return false;
-            mHardwareView.requestRender(mDestroyRunnable.mContext, canvas, false);
+            mHardwareView.requestRender(mContext, canvas, false);
             return true;
         }
 
         @Override
         public boolean requestInvokeGL(View containerView, boolean waitForCompletion) {
             if (!isBackedByHardwareView()) return false;
-            mHardwareView.requestRender(mDestroyRunnable.mContext, null, waitForCompletion);
+            mHardwareView.requestRender(mContext, null, waitForCompletion);
             return true;
         }
 
@@ -487,8 +476,8 @@
         }
 
         @Override
-        public Runnable getDestroyRunnable() {
-            return mDestroyRunnable;
+        public void destroy() {
+            mContext = 0;
         }
     }
 
diff --git a/android_webview/tools/cts_archive/cipd.yaml b/android_webview/tools/cts_archive/cipd.yaml
index 2c2e03c..1ba0f5e 100644
--- a/android_webview/tools/cts_archive/cipd.yaml
+++ b/android_webview/tools/cts_archive/cipd.yaml
@@ -9,5 +9,5 @@
 data:
   - file: arm64/L/android-cts-arm_64-4607260.zip
   - file: arm64/M/android-cts-arm_64-4607285.zip
-  - file: arm64/N/android-cts-arm_64-4606956.zip
-  - file: arm64/O/android-cts-arm_64-4666824.zip
+  - file: arm64/N/android-cts-arm_64-5075646.zip
+  - file: arm64/O/android-cts-arm_64-5075719.zip
diff --git a/android_webview/tools/cts_archive/version.txt b/android_webview/tools/cts_archive/version.txt
index d3827e7..9459d4b 100644
--- a/android_webview/tools/cts_archive/version.txt
+++ b/android_webview/tools/cts_archive/version.txt
@@ -1 +1 @@
-1.0
+1.1
diff --git a/android_webview/tools/cts_config/expected_failure_on_bot.json b/android_webview/tools/cts_config/expected_failure_on_bot.json
index 2676171e..27c6750 100644
--- a/android_webview/tools/cts_config/expected_failure_on_bot.json
+++ b/android_webview/tools/cts_config/expected_failure_on_bot.json
@@ -11,6 +11,14 @@
     {
       "name": "testJavascriptInterfaceCustomPropertiesClearedOnReload",
       "_bug_id": "crbug.com/767847"
+    },
+    {
+      "name": "testRequestImageRef",
+      "_bug_id": "crbug.com/900915"
+    },
+    {
+      "name": "testLoadDataWithBaseUrl",
+      "_bug_id": "crbug.com/900915"
     }
   ],
   "android.webkit.cts.WebSettingsTest": [
@@ -23,12 +31,6 @@
       "_bug_id": "crbug.com/777393"
     }
   ],
-  "android.webkit.cts.WebViewClientTest": [
-    {
-      "name": "testShouldOverrideUrlLoadingOnCreateWindow",
-      "_bug_id": "crbug.com/896857"
-    }
-  ],
   "android.webkit.cts.WebChromeClientTest": [
     {
       "name": "testOnJsBeforeUnloadIsCalled",
diff --git a/android_webview/tools/cts_config/webview_cts_gcs_path.json b/android_webview/tools/cts_config/webview_cts_gcs_path.json
index 5a04aae..5d90979 100644
--- a/android_webview/tools/cts_config/webview_cts_gcs_path.json
+++ b/android_webview/tools/cts_config/webview_cts_gcs_path.json
@@ -1,40 +1,103 @@
 {
+  "_usage":
+  {
+    " The format of this file is as follows.  The excludes and includes lists under test_runs are mutually exclusive, if not specified, all tests in apk will run.":
+    {
+      "<arch>": {
+        "<android SDK Code, such as L, M, N, ...>": {
+          "filename": "<relative path to cts_archive_dir of cts zip>",
+          "_origin":  "<branch@buildid>",
+          "unzip_dir":   "<relative path to work directory where cts should be unzipped to>",
+          "test_runs": [
+          {
+            "apk": "location of the test apk in the cts zip file",
+            "excludes": [
+            {
+              "match": "<class#testcase (wildcard supported) expression of test to skip>",
+              "_bug_id": "<bug reference comment, optional>"
+            }]
+          },
+          {
+            "apk": "location of the test apk in the cts zip file",
+            "includes": [
+            {
+              "match": "<class#testcase (wildcard supported) expression of test to run>"
+            }]
+          }]
+        }
+      }
+    }
+  },
   "arm64": {
     "L": {
-        "filename": "arm64/L/android-cts-arm_64-4607260.zip",
-        "apkdir": "arm64/L/4607260/",
-        "tests": [
-                {"android-cts/repository/testcases/CtsWebkitTestCases.apk": ""},
-                {"android-cts/repository/testcases/CtsWidgetTestCases.apk": "android.widget.cts.RemoteViewsActivityTest#testWebView"}
-        ],
-        "_origin": "aosp-lollipop-mr1-cts-dev@4607260"
+      "filename": "arm64/L/android-cts-arm_64-4607260.zip",
+      "_origin": "aosp-lollipop-mr1-cts-dev@4607260",
+      "unzip_dir": "arm64/L/4607260/",
+      "test_runs": [
+      {
+        "apk": "android-cts/repository/testcases/CtsWebkitTestCases.apk",
+        "excludes": [
+        {
+          "match": "android.webkit.cts.WebViewClientTest#testShouldOverrideUrlLoadingOnCreateWindow",
+          "_bug_id": "crbug.com/896857"
+        }]
+      },
+      {
+        "apk": "android-cts/repository/testcases/CtsWidgetTestCases.apk",
+        "includes": [
+        {
+          "match": "android.widget.cts.RemoteViewsActivityTest#testWebView"
+        }]
+      }]
     },
     "M": {
-        "filename": "arm64/M/android-cts-arm_64-4607285.zip",
-        "apkdir": "arm64/M/4607285/",
-        "tests": [
-                {"android-cts/repository/testcases/CtsWebkitTestCases.apk": ""},
-                {"android-cts/repository/testcases/CtsWidgetTestCases.apk": "android.widget.cts.RemoteViewsActivityTest#testWebView"}
-        ],
-        "_origin": "aosp-marshmallow-cts-dev@4607285"
+      "filename": "arm64/M/android-cts-arm_64-4607285.zip",
+      "_origin": "aosp-marshmallow-cts-dev@4607285",
+      "unzip_dir": "arm64/M/4607285/",
+      "test_runs": [
+      {
+        "apk": "android-cts/repository/testcases/CtsWebkitTestCases.apk",
+        "excludes": [
+        {
+          "match": "android.webkit.cts.WebViewClientTest#testShouldOverrideUrlLoadingOnCreateWindow",
+          "_bug_id": "crbug.com/896857"
+        }]
+      },
+      {
+        "apk": "android-cts/repository/testcases/CtsWidgetTestCases.apk",
+        "includes": [
+        {
+          "match": "android.widget.cts.RemoteViewsActivityTest#testWebView"
+        }]
+      }]
     },
     "N": {
-        "filename": "arm64/N/android-cts-arm_64-4606956.zip",
-        "apkdir": "arm64/N/4606956/",
-        "tests": [
-                {"android-cts/testcases/CtsWebkitTestCases.apk": ""},
-                {"android-cts/testcases/CtsWidgetTestCases.apk": "android.widget.cts.RemoteViewsActivityTest#testWebView"}
-        ],
-        "_origin": "aosp-nougat-cts-release@4606956"
+      "filename": "arm64/N/android-cts-arm_64-5075646.zip",
+      "_origin": "aosp-nougat-cts-dev@5075646",
+      "unzip_dir": "arm64/N/5075646/",
+      "test_runs": [
+      {
+        "apk": "android-cts/testcases/CtsWebkitTestCases.apk"
+      },
+      {
+        "apk": "android-cts/testcases/CtsWidgetTestCases.apk",
+        "includes": [
+        {
+          "match": "android.widget.cts.RemoteViewsActivityTest#testWebView"
+        }]
+      }]
     },
     "O": {
-        "filename": "arm64/O/android-cts-arm_64-4666824.zip",
-        "apkdir": "arm64/O/4666824/",
-        "tests": [
-                {"android-cts/testcases/CtsWebkitTestCases.apk": ""},
-                {"android-cts/testcases/CtsWebViewStartupApp.apk": ""}
-        ],
-        "_origin": "aosp-oreo-cts-release@4666824"
+      "filename": "arm64/O/android-cts-arm_64-5075719.zip",
+      "_origin": "aosp-oreo-cts-dev@5075719",
+      "unzip_dir": "arm64/O/5075719/",
+      "test_runs": [
+      {
+        "apk": "android-cts/testcases/CtsWebkitTestCases.apk"
+      },
+      {
+        "apk": "android-cts/testcases/CtsWebViewStartupApp.apk"
+      }]
     }
   }
 }
diff --git a/android_webview/tools/run_cts.py b/android_webview/tools/run_cts.py
index 062bfd4..3862b46 100755
--- a/android_webview/tools/run_cts.py
+++ b/android_webview/tools/run_cts.py
@@ -75,8 +75,24 @@
                               for m in methods])
   return expected_failures
 
+def GetTestRunFilterArg(test_run, skip_expected_failures):
+  skips = []
+  if skip_expected_failures:
+    skips = GetExpectedFailures()
 
-def RunCTS(test_runner_args, local_cts_dir, apk, test_filter,
+  excludes = test_run.get("excludes", [])
+  includes = test_run.get("includes", [])
+  assert len(excludes) == 0 or len(includes) == 0, \
+         "test_runs error, can't have both includes and excludes: %s" % test_run
+  if len(includes) > 0:
+    return ['-f=' + ':'.join([i["match"] for i in includes])]
+  else:
+    skips.extend([i["match"] for i in excludes])
+    if len(skips) > 0:
+      return ['-f=' + "-" + ':'.join(skips)]
+    return []
+
+def RunCTS(test_runner_args, local_cts_dir, test_run,
            skip_expected_failures=True, json_results_file=None):
   """Run tests in apk using test_runner script at _TEST_RUNNER_PATH.
 
@@ -85,20 +101,22 @@
   is set to False, test results will be stored in
   the json_results_file file if specified
   """
+
+  apk = test_run['apk']
+
   local_test_runner_args = test_runner_args + ['--test-apk',
                                                os.path.join(local_cts_dir, apk)]
 
   # TODO(mikecase): This doesn't work at all with the
   # --gtest-filter test runner option currently. The
   # filter options will just override eachother.
-  if skip_expected_failures:
-    local_test_runner_args += ['-f=-%s' % ':'.join(GetExpectedFailures())]
   # The preferred method is to specify test filters per release in
   # the CTS_GCS path file.  It will override any
   # previous filters, including ones in expected failures
   # file.
-  if test_filter:
-    local_test_runner_args += ['-f=' + test_filter]
+  local_test_runner_args.extend(GetTestRunFilterArg(test_run,
+                                                    skip_expected_failures))
+
   if json_results_file:
     local_test_runner_args += ['--json-results-file=%s' %
                                json_results_file]
@@ -150,7 +168,9 @@
 
   cts_zip_path = os.path.join(_CTS_ARCHIVE_DIR, relative_cts_zip_path)
   local_cts_dir = os.path.join(base_cts_dir,
-                               GetCtsInfo(args.arch, args.platform, 'apkdir'))
+                               GetCtsInfo(args.arch, args.platform,
+                                          'unzip_dir')
+                              )
   zf = zipfile.ZipFile(cts_zip_path, 'r')
   zf.extractall(local_cts_dir)
   return (local_cts_dir, base_cts_dir, delete_cts_dir)
@@ -170,26 +190,25 @@
   cts_result = 0
   json_results_file = args.json_results_file
   try:
-    cts_tests_info = GetCtsInfo(args.arch, args.platform, 'tests')
+    cts_test_runs = GetCtsInfo(args.arch, args.platform, 'test_runs')
     cts_results_json = {}
-    for cts_tests_item in cts_tests_info:
-      for relative_apk_path, test_filter in cts_tests_item.iteritems():
-        iteration_cts_result = 0
-        if json_results_file:
-          with tempfile.NamedTemporaryFile() as iteration_json_file:
-            iteration_cts_result = RunCTS(test_runner_args, local_cts_dir,
-                                          relative_apk_path, test_filter,
-                                          args.skip_expected_failures,
-                                          iteration_json_file.name)
-            with open(iteration_json_file.name) as f:
-              additional_results_json = json.load(f)
-              MergeTestResults(cts_results_json, additional_results_json)
-        else:
+    for cts_test_run in cts_test_runs:
+      iteration_cts_result = 0
+      if json_results_file:
+        with tempfile.NamedTemporaryFile() as iteration_json_file:
           iteration_cts_result = RunCTS(test_runner_args, local_cts_dir,
-                                        relative_apk_path, test_filter,
-                                        args.skip_expected_failures)
-        if iteration_cts_result:
-          cts_result = iteration_cts_result
+                                        cts_test_run,
+                                        args.skip_expected_failures,
+                                        iteration_json_file.name)
+          with open(iteration_json_file.name) as f:
+            additional_results_json = json.load(f)
+            MergeTestResults(cts_results_json, additional_results_json)
+      else:
+        iteration_cts_result = RunCTS(test_runner_args, local_cts_dir,
+                                      cts_test_run,
+                                      args.skip_expected_failures)
+      if iteration_cts_result:
+        cts_result = iteration_cts_result
     if json_results_file:
       with open(json_results_file, 'w') as f:
         json.dump(cts_results_json, f, indent=2)
diff --git a/android_webview/tools/run_cts.pydeps b/android_webview/tools/run_cts.pydeps
index 593d5ff..aa85d32 100644
--- a/android_webview/tools/run_cts.pydeps
+++ b/android_webview/tools/run_cts.pydeps
@@ -54,8 +54,12 @@
 //third_party/catapult/devil/devil/utils/host_utils.py
 //third_party/catapult/devil/devil/utils/lazy/__init__.py
 //third_party/catapult/devil/devil/utils/lazy/weak_constant.py
+//third_party/catapult/devil/devil/utils/logging_common.py
+//third_party/catapult/devil/devil/utils/lsusb.py
 //third_party/catapult/devil/devil/utils/parallelizer.py
 //third_party/catapult/devil/devil/utils/reraiser_thread.py
+//third_party/catapult/devil/devil/utils/reset_usb.py
+//third_party/catapult/devil/devil/utils/run_tests_helper.py
 //third_party/catapult/devil/devil/utils/timeout_retry.py
 //third_party/catapult/devil/devil/utils/watchdog_timer.py
 //third_party/catapult/devil/devil/utils/zip_utils.py
diff --git a/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml b/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml
index d414b04..3d7157b 100644
--- a/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml
+++ b/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml
@@ -10,7 +10,7 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" />
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />
 
     <!-- "Normal" permissions which do not require user prompt -->
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -32,6 +32,7 @@
         android:icon="@drawable/ic_launcher"
         android:label="@string/app_name"
         android:theme="@android:style/Theme.Light"
+        android:networkSecurityConfig="@xml/network_security_config"
         android:debuggable="true" >
         <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
             android:value="true" />
diff --git a/android_webview/tools/system_webview_shell/apk/res/xml/network_security_config.xml b/android_webview/tools/system_webview_shell/apk/res/xml/network_security_config.xml
new file mode 100644
index 0000000..4669e3b
--- /dev/null
+++ b/android_webview/tools/system_webview_shell/apk/res/xml/network_security_config.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<network-security-config>
+    <!-- Starting with Android P (API level 28), the default value of
+    isCleartextTrafficPermitted() is false. For the SystemWebViewShell
+    test browser we explicitly set cleartextTrafficPermitted here to
+    preserve functionality. (crbug.com/898190) -->
+    <base-config cleartextTrafficPermitted="true">
+        <trust-anchors>
+            <certificates src="user"/>
+            <certificates src="system"/>
+        </trust-anchors>
+    </base-config>
+</network-security-config>
\ No newline at end of file
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
index 016b199..b6b480c 100644
--- a/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
@@ -3741,6 +3741,7 @@
     getter origin
     getter ports
     getter source
+    getter userActivation
     method constructor
     method initMessageEvent
 interface MessagePort : EventTarget
@@ -3860,6 +3861,7 @@
     getter product
     getter productSub
     getter serviceWorker
+    getter userActivation
     getter userAgent
     getter vendor
     getter vendorSub
@@ -5818,6 +5820,11 @@
     method sort
     method toString
     method values
+interface UserActivation
+    attribute @@toStringTag
+    getter hasBeenActive
+    getter isActive
+    method constructor
 interface VTTCue : TextTrackCue
     attribute @@toStringTag
     getter align
diff --git a/android_webview/ui/translations/aw_strings_gu.xtb b/android_webview/ui/translations/aw_strings_gu.xtb
index 177424b6..c58019e 100644
--- a/android_webview/ui/translations/aw_strings_gu.xtb
+++ b/android_webview/ui/translations/aw_strings_gu.xtb
@@ -1,9 +1,9 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="gu">
-<translation id="6106989379647458772"><ph name="PAGE" /> પરનું વેબપૃષ્ઠ અસ્થાયી ધોરણે બંધ હોઈ શકે છે અથવા તે કાયમ માટે નવા વેબ સરનામાં પર ખસેડવામાં આવ્યું હોઈ શકે છે.</translation>
-<translation id="6312113039770857350">વેબપૃષ્ઠ ઉપલબ્ધ નથી</translation>
-<translation id="8681531050781943054"><ph name="PAGE" /> પરનું વેબપૃષ્ઠ લોડ કરી શકાયું નથી કારણ કે:</translation>
+<translation id="6106989379647458772"><ph name="PAGE" /> પરનું વેબપેજ થોડી વાર માટે બંધ હોઈ શકે છે અથવા તે કાયમ માટે નવા વેબ ઍડ્રેસ પર ખસેડવામાં આવ્યું હોઈ શકે છે.</translation>
+<translation id="6312113039770857350">વેબપેજ ઉપલબ્ધ નથી</translation>
+<translation id="8681531050781943054"><ph name="PAGE" /> પરનું વેબપેજ લોડ કરી શકાયું નથી કારણ કે:</translation>
 <translation id="8882178685025065378">અરેરે! <ph name="PAGE" /> ની મુલાકાત લો છો તે ઠીક છે કે કેમ તે તમારે તમારા માતાપિતાને પૂછવાની જરૂર છે.</translation>
-<translation id="8963213021028234748"><ph name="MARKUP_1" />સૂચનો:<ph name="MARKUP_2" />ખાતરી કરો કે તમારી પાસે ડેટા કનેક્શન છે<ph name="MARKUP_3" />આ વેબપૃષ્ઠને પછીથી ફરી લોડ કરો<ph name="MARKUP_4" />તમે દાખલ કરેલ સરનામું તપાસો<ph name="MARKUP_5" /></translation>
+<translation id="8963213021028234748"><ph name="MARKUP_1" />સૂચનો:<ph name="MARKUP_2" />ખાતરી કરો કે તમારી પાસે ડેટા કનેક્શન છે<ph name="MARKUP_3" />આ વેબપેજને પછીથી ફરી લોડ કરો<ph name="MARKUP_4" />તમે દાખલ કરેલું ઍડ્રેસ તપાસો<ph name="MARKUP_5" /></translation>
 </translationbundle>
\ No newline at end of file
diff --git a/apps/launcher.cc b/apps/launcher.cc
index 6da9c0d..aeb55f7 100644
--- a/apps/launcher.cc
+++ b/apps/launcher.cc
@@ -134,7 +134,7 @@
       return;
 
     if (entry_paths_.empty()) {
-      LaunchWithNoLaunchData();
+      LaunchWithBasicData();
       return;
     }
 
@@ -174,7 +174,8 @@
         LOG(WARNING) << "Cannot make absolute path from " << it->value();
         base::PostTaskWithTraits(
             FROM_HERE, {BrowserThread::UI},
-            base::Bind(&PlatformAppPathLauncher::LaunchWithNoLaunchData, this));
+            base::BindOnce(&PlatformAppPathLauncher::LaunchWithBasicData,
+                           this));
         return;
       }
     }
@@ -193,10 +194,10 @@
   }
 
   void OnFilesInvalid(const base::FilePath& /* error_path */) {
-    LaunchWithNoLaunchData();
+    LaunchWithBasicData();
   }
 
-  void LaunchWithNoLaunchData() {
+  void LaunchWithBasicData() {
     // This method is required as an entry point on the UI thread.
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -207,6 +208,8 @@
     std::unique_ptr<app_runtime::LaunchData> launch_data =
         std::make_unique<app_runtime::LaunchData>();
     launch_data->action_data = std::move(action_data_);
+    if (!handler_id_.empty())
+      launch_data->id = std::make_unique<std::string>(handler_id_);
 
     AppRuntimeEventRouter::DispatchOnLaunchedEvent(
         context_, app, launch_source_, std::move(launch_data));
@@ -274,7 +277,7 @@
     // with no launch data.
     if (!handler) {
       LOG(WARNING) << "Extension does not provide a valid file handler.";
-      LaunchWithNoLaunchData();
+      LaunchWithBasicData();
       return;
     }
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 5df107c..711dce4 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -62,7 +62,6 @@
     "system/status_area_widget.h",
     "system/status_area_widget_delegate.h",
     "system/system_tray_focus_observer.h",
-    "system/tray/system_tray.h",
     "system/tray/system_tray_notifier.h",
     "system/unified/unified_system_tray.h",
     "touch/touch_observer_hud.h",
@@ -85,6 +84,7 @@
     "wm/window_util.h",
     "wm/wm_event.h",
     "wm/workspace/workspace_window_resizer.h",
+    "ws/window_lookup.h",
   ]
   sources = [
     "accelerators/accelerator_commands.cc",
@@ -585,6 +585,8 @@
     "shelf/shelf_constants.h",
     "shelf/shelf_context_menu_model.cc",
     "shelf/shelf_context_menu_model.h",
+    "shelf/shelf_control_button.cc",
+    "shelf/shelf_control_button.h",
     "shelf/shelf_controller.cc",
     "shelf/shelf_controller.h",
     "shelf/shelf_layout_manager.cc",
@@ -642,16 +644,12 @@
     "system/audio/audio_detailed_view.h",
     "system/audio/display_speaker_controller.cc",
     "system/audio/display_speaker_controller.h",
-    "system/audio/tray_audio.cc",
-    "system/audio/tray_audio.h",
     "system/audio/unified_audio_detailed_view_controller.cc",
     "system/audio/unified_audio_detailed_view_controller.h",
     "system/audio/unified_volume_slider_controller.cc",
     "system/audio/unified_volume_slider_controller.h",
     "system/audio/unified_volume_view.cc",
     "system/audio/unified_volume_view.h",
-    "system/audio/volume_view.cc",
-    "system/audio/volume_view.h",
     "system/bluetooth/bluetooth_detailed_view.cc",
     "system/bluetooth/bluetooth_detailed_view.h",
     "system/bluetooth/bluetooth_feature_pod_controller.cc",
@@ -661,8 +659,6 @@
     "system/bluetooth/bluetooth_observer.h",
     "system/bluetooth/bluetooth_power_controller.cc",
     "system/bluetooth/bluetooth_power_controller.h",
-    "system/bluetooth/tray_bluetooth.cc",
-    "system/bluetooth/tray_bluetooth.h",
     "system/bluetooth/tray_bluetooth_helper.cc",
     "system/bluetooth/tray_bluetooth_helper.h",
     "system/bluetooth/tray_bluetooth_helper_experimental.cc",
@@ -673,8 +669,6 @@
     "system/bluetooth/unified_bluetooth_detailed_view_controller.h",
     "system/brightness/brightness_controller_chromeos.cc",
     "system/brightness/brightness_controller_chromeos.h",
-    "system/brightness/tray_brightness.cc",
-    "system/brightness/tray_brightness.h",
     "system/brightness/unified_brightness_slider_controller.cc",
     "system/brightness/unified_brightness_slider_controller.h",
     "system/brightness/unified_brightness_view.cc",
@@ -693,19 +687,9 @@
     "system/date/clock_observer.h",
     "system/date/date_view.cc",
     "system/date/date_view.h",
-    "system/date/system_info_default_view.cc",
-    "system/date/system_info_default_view.h",
     "system/date/tray_system_info.cc",
     "system/date/tray_system_info.h",
-    "system/display_scale/scale_detailed_view.cc",
-    "system/display_scale/scale_detailed_view.h",
-    "system/display_scale/scale_view.cc",
-    "system/display_scale/scale_view.h",
-    "system/display_scale/tray_scale.cc",
-    "system/display_scale/tray_scale.h",
     "system/enterprise/enterprise_domain_observer.h",
-    "system/enterprise/tray_enterprise.cc",
-    "system/enterprise/tray_enterprise.h",
     "system/flag_warning/flag_warning_tray.cc",
     "system/flag_warning/flag_warning_tray.h",
     "system/ime/ime_feature_pod_controller.cc",
@@ -721,15 +705,11 @@
     "system/ime_menu/ime_menu_tray.h",
     "system/keyboard_brightness/keyboard_brightness_controller.cc",
     "system/keyboard_brightness/keyboard_brightness_controller.h",
-    "system/keyboard_brightness/tray_keyboard_brightness.cc",
-    "system/keyboard_brightness/tray_keyboard_brightness.h",
     "system/keyboard_brightness/unified_keyboard_brightness_slider_controller.cc",
     "system/keyboard_brightness/unified_keyboard_brightness_slider_controller.h",
     "system/keyboard_brightness_control_delegate.h",
     "system/locale/locale_notification_controller.cc",
     "system/locale/locale_notification_controller.h",
-    "system/media_security/multi_profile_media_tray_item.cc",
-    "system/media_security/multi_profile_media_tray_item.h",
     "system/message_center/arc_notification_manager_delegate_impl.cc",
     "system/message_center/arc_notification_manager_delegate_impl.h",
     "system/message_center/ash_message_center_lock_screen_controller.cc",
@@ -796,8 +776,6 @@
     "system/network/network_tray_view.h",
     "system/network/sms_observer.cc",
     "system/network/sms_observer.h",
-    "system/network/tray_network.cc",
-    "system/network/tray_network.h",
     "system/network/tray_network_state_observer.cc",
     "system/network/tray_network_state_observer.h",
     "system/network/tray_vpn.cc",
@@ -822,8 +800,6 @@
     "system/night_light/night_light_toggle_button.h",
     "system/night_light/time_of_day.cc",
     "system/night_light/time_of_day.h",
-    "system/night_light/tray_night_light.cc",
-    "system/night_light/tray_night_light.h",
     "system/overview/overview_button_tray.cc",
     "system/overview/overview_button_tray.h",
     "system/palette/common_palette_tool.cc",
@@ -892,22 +868,14 @@
     "system/power/video_activity_notifier.h",
     "system/rotation/rotation_lock_feature_pod_controller.cc",
     "system/rotation/rotation_lock_feature_pod_controller.h",
-    "system/rotation/tray_rotation_lock.cc",
-    "system/rotation/tray_rotation_lock.h",
     "system/screen_layout_observer.cc",
     "system/screen_layout_observer.h",
     "system/screen_security/screen_capture_observer.h",
-    "system/screen_security/screen_capture_tray_item.cc",
-    "system/screen_security/screen_capture_tray_item.h",
     "system/screen_security/screen_security_notification_controller.cc",
     "system/screen_security/screen_security_notification_controller.h",
     "system/screen_security/screen_share_observer.h",
-    "system/screen_security/screen_share_tray_item.cc",
-    "system/screen_security/screen_share_tray_item.h",
     "system/screen_security/screen_switch_check_controller.cc",
     "system/screen_security/screen_switch_check_controller.h",
-    "system/screen_security/screen_tray_item.cc",
-    "system/screen_security/screen_tray_item.h",
     "system/session/logout_button_tray.cc",
     "system/session/logout_button_tray.h",
     "system/session/logout_confirmation_controller.cc",
@@ -916,8 +884,6 @@
     "system/session/logout_confirmation_dialog.h",
     "system/session/session_limit_notification_controller.cc",
     "system/session/session_limit_notification_controller.h",
-    "system/session/tray_session_length_limit.cc",
-    "system/session/tray_session_length_limit.h",
     "system/status_area_layout_manager.cc",
     "system/status_area_layout_manager.h",
     "system/status_area_widget.cc",
@@ -926,14 +892,8 @@
     "system/supervised/supervised_icon_string.h",
     "system/supervised/supervised_notification_controller.cc",
     "system/supervised/supervised_notification_controller.h",
-    "system/supervised/tray_supervised_user.cc",
-    "system/supervised/tray_supervised_user.h",
     "system/system_notification_controller.cc",
     "system/system_notification_controller.h",
-    "system/tiles/tiles_default_view.cc",
-    "system/tiles/tiles_default_view.h",
-    "system/tiles/tray_tiles.cc",
-    "system/tiles/tray_tiles.h",
     "system/toast/toast_data.cc",
     "system/toast/toast_data.h",
     "system/toast/toast_manager.cc",
@@ -955,17 +915,8 @@
     "system/tray/size_range_layout.h",
     "system/tray/system_menu_button.cc",
     "system/tray/system_menu_button.h",
-    "system/tray/system_tray.cc",
-    "system/tray/system_tray_bubble.cc",
-    "system/tray/system_tray_bubble.h",
-    "system/tray/system_tray_item.cc",
-    "system/tray/system_tray_item.h",
-    "system/tray/system_tray_item_detailed_view_delegate.cc",
-    "system/tray/system_tray_item_detailed_view_delegate.h",
     "system/tray/system_tray_item_uma_type.h",
     "system/tray/system_tray_notifier.cc",
-    "system/tray/system_tray_view.cc",
-    "system/tray/system_tray_view.h",
     "system/tray/time_to_click_recorder.cc",
     "system/tray/time_to_click_recorder.h",
     "system/tray/tray_background_view.cc",
@@ -983,12 +934,8 @@
     "system/tray/tray_detailed_view.h",
     "system/tray/tray_event_filter.cc",
     "system/tray/tray_event_filter.h",
-    "system/tray/tray_image_item.cc",
-    "system/tray/tray_image_item.h",
     "system/tray/tray_info_label.cc",
     "system/tray/tray_info_label.h",
-    "system/tray/tray_item_more.cc",
-    "system/tray/tray_item_more.h",
     "system/tray/tray_item_view.cc",
     "system/tray/tray_item_view.h",
     "system/tray/tray_popup_ink_drop_style.h",
@@ -1001,12 +948,8 @@
     "system/tray/tri_view.cc",
     "system/tray/tri_view.h",
     "system/tray/view_click_listener.h",
-    "system/tray_caps_lock.cc",
-    "system/tray_caps_lock.h",
     "system/tray_drag_controller.cc",
     "system/tray_drag_controller.h",
-    "system/tray_tracing.cc",
-    "system/tray_tracing.h",
     "system/unified/collapse_button.cc",
     "system/unified/collapse_button.h",
     "system/unified/detailed_view_controller.h",
@@ -1053,22 +996,12 @@
     "system/unified/unified_system_tray_view.h",
     "system/unified/user_chooser_view.cc",
     "system/unified/user_chooser_view.h",
-    "system/update/tray_update.cc",
-    "system/update/tray_update.h",
     "system/update/update_notification_controller.cc",
     "system/update/update_notification_controller.h",
-    "system/user/button_from_view.cc",
-    "system/user/button_from_view.h",
     "system/user/login_status.cc",
     "system/user/login_status.h",
     "system/user/rounded_image_view.cc",
     "system/user/rounded_image_view.h",
-    "system/user/tray_user.cc",
-    "system/user/tray_user.h",
-    "system/user/user_card_view.cc",
-    "system/user/user_card_view.h",
-    "system/user/user_view.cc",
-    "system/user/user_view.h",
     "system/virtual_keyboard/virtual_keyboard_observer.h",
     "system/virtual_keyboard/virtual_keyboard_tray.cc",
     "system/virtual_keyboard/virtual_keyboard_tray.h",
@@ -1140,10 +1073,8 @@
     "wm/gestures/overview_gesture_handler.h",
     "wm/immersive_context_ash.cc",
     "wm/immersive_context_ash.h",
-    "wm/immersive_gesture_handler_classic.cc",
-    "wm/immersive_gesture_handler_classic.h",
-    "wm/immersive_handler_factory_ash.cc",
-    "wm/immersive_handler_factory_ash.h",
+    "wm/immersive_gesture_drag_handler.cc",
+    "wm/immersive_gesture_drag_handler.h",
     "wm/lock_action_handler_layout_manager.cc",
     "wm/lock_action_handler_layout_manager.h",
     "wm/lock_layout_manager.cc",
@@ -1234,9 +1165,8 @@
     "wm/system_modal_container_layout_manager.h",
     "wm/system_wallpaper_controller.cc",
     "wm/system_wallpaper_controller.h",
-    "wm/tablet_mode/scoped_disable_internal_mouse_and_keyboard.h",
-    "wm/tablet_mode/scoped_disable_internal_mouse_and_keyboard_ozone.cc",
-    "wm/tablet_mode/scoped_disable_internal_mouse_and_keyboard_ozone.h",
+    "wm/tablet_mode/internal_input_devices_event_blocker.cc",
+    "wm/tablet_mode/internal_input_devices_event_blocker.h",
     "wm/tablet_mode/scoped_skip_user_session_blocked_check.cc",
     "wm/tablet_mode/scoped_skip_user_session_blocked_check.h",
     "wm/tablet_mode/tablet_mode_app_window_drag_controller.cc",
@@ -1321,6 +1251,7 @@
     "ws/ash_gpu_interface_provider.h",
     "ws/ash_window_manager.cc",
     "ws/ash_window_manager.h",
+    "ws/window_lookup.cc",
     "ws/window_service_delegate_impl.cc",
     "ws/window_service_delegate_impl.h",
     "ws/window_service_owner.cc",
@@ -1805,20 +1736,13 @@
     "system/accessibility/dictation_button_tray_unittest.cc",
     "system/accessibility/select_to_speak_tray_unittest.cc",
     "system/accessibility/tray_accessibility_unittest.cc",
-    "system/audio/tray_audio_unittest.cc",
     "system/bluetooth/bluetooth_power_controller_unittest.cc",
     "system/bluetooth/tray_bluetooth_helper_legacy_unittest.cc",
-    "system/brightness/tray_brightness_unittest.cc",
     "system/caps_lock_notification_controller_unittest.cc",
     "system/date/date_view_unittest.cc",
-    "system/date/system_info_default_view_unittest.cc",
-    "system/enterprise/tray_enterprise_unittest.cc",
     "system/flag_warning/flag_warning_tray_unittest.cc",
     "system/ime/ime_feature_pod_controller_unittest.cc",
-    "system/ime/tray_ime_chromeos_unittest.cc",
     "system/ime_menu/ime_menu_tray_unittest.cc",
-    "system/keyboard_brightness/tray_keyboard_brightness_unittest.cc",
-    "system/media_security/multi_profile_media_tray_item_unittest.cc",
     "system/message_center/arc/arc_notification_content_view_unittest.cc",
     "system/message_center/arc/arc_notification_manager_unittest.cc",
     "system/message_center/arc/arc_notification_view_unittest.cc",
@@ -1832,12 +1756,10 @@
     "system/network/auto_connect_notifier_unittest.cc",
     "system/network/network_icon_unittest.cc",
     "system/network/sms_observer_unittest.cc",
-    "system/network/tray_network_unittest.cc",
     "system/network/vpn_list_unittest.cc",
     "system/network/wifi_toggle_notification_controller_unittest.cc",
     "system/night_light/night_light_controller_unittest.cc",
     "system/night_light/time_of_day_unittest.cc",
-    "system/night_light/tray_night_light_unittest.cc",
     "system/overview/overview_button_tray_unittest.cc",
     "system/palette/mock_palette_tool_delegate.cc",
     "system/palette/mock_palette_tool_delegate.h",
@@ -1858,36 +1780,26 @@
     "system/power/power_status_view_unittest.cc",
     "system/power/video_activity_notifier_unittest.cc",
     "system/rotation/rotation_lock_feature_pod_controller_unittest.cc",
-    "system/rotation/tray_rotation_lock_unittest.cc",
     "system/screen_layout_observer_unittest.cc",
     "system/screen_security/screen_security_notification_controller_unittest.cc",
-    "system/screen_security/screen_tray_item_unittest.cc",
     "system/session/logout_button_tray_unittest.cc",
     "system/session/logout_confirmation_controller_unittest.cc",
     "system/session/session_limit_notification_controller_unittest.cc",
-    "system/session/tray_session_length_limit_unittest.cc",
     "system/status_area_widget_unittest.cc",
     "system/supervised/supervised_notification_controller_unittest.cc",
-    "system/supervised/tray_supervised_user_unittest.cc",
-    "system/tiles/tray_tiles_unittest.cc",
     "system/toast/toast_manager_unittest.cc",
     "system/tracing_notification_controller_unittest.cc",
     "system/tray/size_range_layout_unittest.cc",
-    "system/tray/system_tray_unittest.cc",
-    "system/tray/tray_detailed_view_unittest.cc",
     "system/tray/tray_event_filter_unittest.cc",
     "system/tray/tray_info_label_unittest.cc",
     "system/tray/tri_view_unittest.cc",
-    "system/tray_tracing_unittest.cc",
     "system/unified/feature_pods_container_view_unittest.cc",
     "system/unified/quiet_mode_feature_pod_controller_unittest.cc",
     "system/unified/top_shortcuts_view_unittest.cc",
     "system/unified/unified_system_info_view_unittest.cc",
     "system/unified/unified_system_tray_controller_unittest.cc",
     "system/unified/unified_system_tray_unittest.cc",
-    "system/update/tray_update_unittest.cc",
     "system/update/update_notification_controller_unittest.cc",
-    "system/user/tray_user_unittest.cc",
     "system/virtual_keyboard/virtual_keyboard_tray_unittest.cc",
     "test/ash_test_helper_unittest.cc",
     "test/ash_unittests.cc",
@@ -2236,10 +2148,6 @@
     "system/status_area_widget_test_api.h",
     "system/status_area_widget_test_helper.cc",
     "system/status_area_widget_test_helper.h",
-    "system/tray/system_tray_test_api.cc",
-    "system/tray/system_tray_test_api.h",
-    "system/tray/test_system_tray_item.cc",
-    "system/tray/test_system_tray_item.h",
     "system/unified/unified_system_tray_test_api.cc",
     "system/unified/unified_system_tray_test_api.h",
     "test/ash_test_base.cc",
@@ -2331,6 +2239,7 @@
     "//ui/gl",
     "//ui/gl:test_support",
     "//ui/keyboard",
+    "//ui/keyboard:test_support",
     "//ui/message_center",
     "//ui/message_center/public/cpp",
     "//ui/views",
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 1edb836..106d5b1 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -31,6 +31,7 @@
 #include "ash/new_window_controller.h"
 #include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/ash_features.h"
+#include "ash/public/cpp/notification_utils.h"
 #include "ash/public/interfaces/accessibility_controller.mojom.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
@@ -159,16 +160,14 @@
               Shell::Get()->shell_delegate()->OpenKeyboardShortcutHelpPage();
           }));
 
-  std::unique_ptr<Notification> notification =
-      message_center::Notification::CreateSystemNotification(
-          message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
-          l10n_util::GetStringUTF16(IDS_DEPRECATED_SHORTCUT_TITLE), message,
-          base::string16(), GURL(),
-          message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT,
-              kNotifierAccelerator),
-          message_center::RichNotificationData(), std::move(delegate),
-          kNotificationKeyboardIcon, SystemNotificationWarningLevel::NORMAL);
+  std::unique_ptr<Notification> notification = ash::CreateSystemNotification(
+      message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
+      l10n_util::GetStringUTF16(IDS_DEPRECATED_SHORTCUT_TITLE), message,
+      base::string16(), GURL(),
+      message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
+                                 kNotifierAccelerator),
+      message_center::RichNotificationData(), std::move(delegate),
+      kNotificationKeyboardIcon, SystemNotificationWarningLevel::NORMAL);
   notification->set_priority(message_center::SYSTEM_PRIORITY);
   message_center::MessageCenter::Get()->AddNotification(
       std::move(notification));
@@ -497,15 +496,10 @@
 }
 
 void HandleToggleAppList(const ui::Accelerator& accelerator) {
-  if (Shell::Get()
-          ->app_list_controller()
-          ->IsHomeLauncherEnabledInTabletMode()) {
-    return;
-  }
   if (accelerator.key_code() == ui::VKEY_LWIN)
     base::RecordAction(UserMetricsAction("Accel_Search_LWin"));
 
-  Shell::Get()->app_list_controller()->ToggleAppList(
+  Shell::Get()->app_list_controller()->OnAppListButtonPressed(
       display::Screen::GetScreen()
           ->GetDisplayNearestWindow(Shell::GetRootWindowForNewWindows())
           .id(),
@@ -660,7 +654,9 @@
         base::UserMetricsAction("VoiceInteraction.Started.Assistant"));
   }
 
-  switch (Shell::Get()->voice_interaction_controller()->allowed_state()) {
+  switch (
+      Shell::Get()->voice_interaction_controller()->allowed_state().value_or(
+          mojom::AssistantAllowedState::ALLOWED)) {
     case mojom::AssistantAllowedState::DISALLOWED_BY_NONPRIMARY_USER:
       // Show a toast if the active user is not primary.
       ShowToast(kVoiceInteractionErrorToastId,
@@ -802,21 +798,28 @@
   return features::IsDockedMagnifierEnabled();
 }
 
+bool CanHandleToggleOverview() {
+  auto windows = Shell::Get()->mru_window_tracker()->BuildMruWindowList();
+  // Do not toggle overview if there is a window being dragged.
+  for (auto* window : windows) {
+    if (wm::GetWindowState(window)->is_dragged())
+      return false;
+  }
+  return true;
+}
+
 void CreateAndShowStickyNotification(const int title_id,
                                      const int message_id,
                                      const std::string& notification_id) {
-  std::unique_ptr<Notification> notification =
-      Notification::CreateSystemNotification(
-          message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
-          l10n_util::GetStringUTF16(title_id),
-          l10n_util::GetStringUTF16(message_id),
-          base::string16() /* display source */, GURL(),
-          message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT,
-              kNotifierAccelerator),
-          message_center::RichNotificationData(), nullptr,
-          kNotificationAccessibilityIcon,
-          SystemNotificationWarningLevel::NORMAL);
+  std::unique_ptr<Notification> notification = ash::CreateSystemNotification(
+      message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
+      l10n_util::GetStringUTF16(title_id),
+      l10n_util::GetStringUTF16(message_id),
+      base::string16() /* display source */, GURL(),
+      message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
+                                 kNotifierAccelerator),
+      message_center::RichNotificationData(), nullptr,
+      kNotificationAccessibilityIcon, SystemNotificationWarningLevel::NORMAL);
   notification->set_priority(message_center::SYSTEM_PRIORITY);
   message_center::MessageCenter::Get()->AddNotification(
       std::move(notification));
@@ -1317,6 +1320,8 @@
       return true;
     case TOGGLE_MIRROR_MODE:
       return true;
+    case TOGGLE_OVERVIEW:
+      return CanHandleToggleOverview();
     case TOUCH_HUD_CLEAR:
     case TOUCH_HUD_MODE_CHANGE:
       return CanHandleTouchHud();
@@ -1372,7 +1377,6 @@
     case TOGGLE_FULLSCREEN:
     case TOGGLE_HIGH_CONTRAST:
     case TOGGLE_MAXIMIZED:
-    case TOGGLE_OVERVIEW:
     case TOGGLE_SPOKEN_FEEDBACK:
     case TOGGLE_SYSTEM_TRAY_BUBBLE:
     case TOGGLE_WIFI:
diff --git a/ash/accelerators/debug_commands.cc b/ash/accelerators/debug_commands.cc
index f75a57b..41554aa 100644
--- a/ash/accelerators/debug_commands.cc
+++ b/ash/accelerators/debug_commands.cc
@@ -13,8 +13,10 @@
 #include "ash/system/toast/toast_manager.h"
 #include "ash/touch/touch_devices_controller.h"
 #include "ash/wallpaper/wallpaper_controller.h"
+#include "ash/wm/focus_rules.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/widget_finder.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/ws/window_service_owner.h"
 #include "base/command_line.h"
@@ -72,8 +74,10 @@
   const gfx::Vector2dF& subpixel_position_offset =
       window->layer()->subpixel_position_offset();
   *out << indent_str << name << " (" << window << ")"
-       << " type=" << window->type()
-       << ((window == active_window) ? " [active]" : "")
+       << " type=" << window->type();
+  if (ash::IsToplevelWindow(window))
+    *out << " " << wm::GetWindowState(window)->GetStateType();
+  *out << ((window == active_window) ? " [active]" : "")
        << ((window == focused_window) ? " [focused]" : "")
        << (window->IsVisible() ? " visible" : "") << " "
        << window->bounds().ToString();
diff --git a/ash/accelerators/pre_target_accelerator_handler.cc b/ash/accelerators/pre_target_accelerator_handler.cc
index f11fad1..aac0d3f 100644
--- a/ash/accelerators/pre_target_accelerator_handler.cc
+++ b/ash/accelerators/pre_target_accelerator_handler.cc
@@ -5,7 +5,6 @@
 #include "ash/accelerators/pre_target_accelerator_handler.h"
 
 #include "ash/accelerators/accelerator_controller.h"
-#include "ash/app_list/app_list_controller_impl.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/shell.h"
 #include "ash/wm/window_state.h"
@@ -136,10 +135,7 @@
 
   // Handle preferred accelerators (such as ALT-TAB) before sending
   // to the target.
-  if (accelerator_controller->IsPreferred(accelerator))
-    return true;
-
-  return Shell::Get()->app_list_controller()->GetTargetVisibility();
+  return accelerator_controller->IsPreferred(accelerator);
 }
 
 }  // namespace ash
diff --git a/ash/accessibility/accessibility_controller.cc b/ash/accessibility/accessibility_controller.cc
index ac02fd1..3f7d9bf 100644
--- a/ash/accessibility/accessibility_controller.cc
+++ b/ash/accessibility/accessibility_controller.cc
@@ -16,6 +16,7 @@
 #include "ash/high_contrast/high_contrast_controller.h"
 #include "ash/policy/policy_recommendation_restorer.h"
 #include "ash/public/cpp/ash_pref_names.h"
+#include "ash/public/cpp/notification_utils.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
@@ -210,11 +211,11 @@
   message_center::RichNotificationData options;
   options.should_make_spoken_feedback_for_popup_updates = false;
   std::unique_ptr<message_center::Notification> notification =
-      message_center::Notification::CreateSystemNotification(
+      ash::CreateSystemNotification(
           message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, title,
           text, base::string16(), GURL(),
           message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT,
+              message_center::NotifierType::SYSTEM_COMPONENT,
               kNotifierAccessibility),
           options, nullptr, GetNotificationIcon(type),
           message_center::SystemNotificationWarningLevel::NORMAL);
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn
index 260da88..f19efa8 100644
--- a/ash/app_list/BUILD.gn
+++ b/ash/app_list/BUILD.gn
@@ -110,6 +110,7 @@
     "//components/keyed_service/core",
     "//components/sync",
     "//mojo/public/cpp/bindings",
+    "//services/content/public/cpp",
     "//services/ws/public/cpp",
     "//services/ws/public/mojom",
     "//services/ws/remote_view_host",
@@ -137,11 +138,14 @@
   public_deps = [
     "//ash/app_list/model:app_list_model",
     "//ash/app_list/model:search_model",
-    "//ash/public/cpp:cpp",
+    "//ash/public/cpp",
+    "//services/content/public/mojom",
   ]
 }
 
 static_library("test_support") {
+  testonly = true
+
   sources = [
     "test/app_list_test_model.cc",
     "test/app_list_test_model.h",
@@ -156,6 +160,7 @@
   deps = [
     ":app_list",
     "//base",
+    "//services/content/public/cpp/test:test_support",
     "//ui/base:base",
     "//ui/events",
     "//ui/gfx",
@@ -215,6 +220,10 @@
     "//base",
     "//base/test:test_support",
     "//mojo/core/embedder",
+    "//mojo/public/cpp/bindings",
+    "//services/content/public/cpp",
+    "//services/content/public/cpp/test:test_support",
+    "//services/content/public/mojom",
     "//skia",
     "//testing/gtest",
     "//ui/accessibility",
diff --git a/ash/app_list/DEPS b/ash/app_list/DEPS
index 5bb4d79d..f6dc209 100644
--- a/ash/app_list/DEPS
+++ b/ash/app_list/DEPS
@@ -3,6 +3,7 @@
   "+components/keyed_service/core",
   "+components/sync",
   "+mojo/public/cpp",
+  "+net/http/http_response_headers.h",
   "+services/ws/public",
   "+skia",
   "+third_party/google_toolbox_for_mac/src",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 62becee..f55ce09 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -19,31 +19,39 @@
 #include "ash/assistant/assistant_ui_controller.h"
 #include "ash/public/cpp/app_list/answer_card_contents_registry.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
+#include "ash/public/cpp/shell_window_ids.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/voice_interaction/voice_interaction_controller.h"
 #include "ash/wallpaper/wallpaper_controller.h"
+#include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overview/window_selector_controller.h"
+#include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/window_state.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "extensions/common/constants.h"
 #include "ui/base/ui_base_features.h"
+#include "ui/display/manager/display_manager.h"
 #include "ui/display/screen.h"
 
 namespace ash {
 
-AppListControllerImpl::AppListControllerImpl(ws::WindowService* window_service)
-    : window_service_(window_service),
-      presenter_(std::make_unique<AppListPresenterDelegateImpl>(this)),
+AppListControllerImpl::AppListControllerImpl()
+    : presenter_(std::make_unique<AppListPresenterDelegateImpl>(this)),
       is_home_launcher_enabled_(app_list_features::IsHomeLauncherEnabled()),
       voice_interaction_binding_(this) {
   model_.AddObserver(this);
 
   // Create only for non-mash. Mash uses window tree embed API to get a
   // token to map answer card contents.
+  //
+  // TODO(https://crbug.com/894987): This is now only used (as a singleton) by
+  // assistant UI code to display its answer card contents. It can be removed
+  // once that code is ported to use Content Service.
   if (!::features::IsUsingWindowService()) {
     answer_card_contents_registry_ =
         std::make_unique<app_list::AnswerCardContentsRegistry>();
@@ -602,6 +610,61 @@
   presenter_.GetView()->Back();
 }
 
+void AppListControllerImpl::OnAppListButtonPressed(
+    int64_t display_id,
+    app_list::AppListShowSource show_source,
+    base::TimeTicks event_time_stamp) {
+  if (!IsHomeLauncherEnabledInTabletMode()) {
+    ToggleAppList(display_id, show_source, event_time_stamp);
+    return;
+  }
+
+  // Whether the this action is handled.
+  bool handled = false;
+
+  if (home_launcher_gesture_handler_) {
+    handled = home_launcher_gesture_handler_->ShowHomeLauncher(
+        Shell::Get()->display_manager()->GetDisplayForId(display_id));
+  }
+
+  if (!handled) {
+    if (Shell::Get()->window_selector_controller()->IsSelecting()) {
+      // End overview mode.
+      Shell::Get()->window_selector_controller()->ToggleOverview(
+          WindowSelector::EnterExitOverviewType::kWindowsMinimized);
+      handled = true;
+    }
+    if (Shell::Get()->split_view_controller()->IsSplitViewModeActive()) {
+      // End split view mode.
+      Shell::Get()->split_view_controller()->EndSplitView(
+          SplitViewController::EndReason::kHomeLauncherPressed);
+      handled = true;
+    }
+  }
+
+  if (!handled) {
+    // Minimize all windows that aren't the app list in reverse order to
+    // preserve the mru ordering.
+    aura::Window* app_list_container =
+        Shell::Get()->GetPrimaryRootWindow()->GetChildById(
+            kShellWindowId_AppListTabletModeContainer);
+    aura::Window::Windows windows =
+        Shell::Get()->mru_window_tracker()->BuildWindowForCycleList();
+    std::reverse(windows.begin(), windows.end());
+    for (auto* window : windows) {
+      if (!app_list_container->Contains(window) &&
+          !wm::GetWindowState(window)->IsMinimized()) {
+        wm::GetWindowState(window)->Minimize();
+        handled = true;
+      }
+    }
+  }
+
+  // Perform the "back" action for the app list.
+  if (!handled)
+    Back();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Methods of |client_|:
 
@@ -771,8 +834,10 @@
          HomeLauncherGestureHandler::Mode::kSlideUpToShow;
 }
 
-ws::WindowService* AppListControllerImpl::GetWindowService() {
-  return window_service_;
+void AppListControllerImpl::GetNavigableContentsFactory(
+    content::mojom::NavigableContentsFactoryRequest request) {
+  if (client_)
+    client_->GetNavigableContentsFactory(std::move(request));
 }
 
 void AppListControllerImpl::OnVisibilityChanged(bool visible) {
@@ -875,7 +940,7 @@
 
   auto* controller = Shell::Get()->voice_interaction_controller();
   GetSearchModel()->search_box()->SetShowAssistantButton(
-      controller->settings_enabled() &&
+      controller->settings_enabled().value_or(false) &&
       controller->allowed_state() == mojom::AssistantAllowedState::ALLOWED);
 }
 
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 6e4ae13..732e544 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -37,10 +37,6 @@
 class MouseWheelEvent;
 }  // namespace ui
 
-namespace ws {
-class WindowService;
-}  // namespace ws
-
 namespace ash {
 
 class HomeLauncherGestureHandler;
@@ -61,7 +57,7 @@
  public:
   using AppListItemMetadataPtr = mojom::AppListItemMetadataPtr;
   using SearchResultMetadataPtr = mojom::SearchResultMetadataPtr;
-  explicit AppListControllerImpl(ws::WindowService* window_service);
+  AppListControllerImpl();
   ~AppListControllerImpl() override;
 
   // Binds the mojom::AppListController interface request to this object.
@@ -185,7 +181,8 @@
   bool ProcessHomeLauncherGesture(ui::GestureEvent* event,
                                   const gfx::Point& screen_location) override;
   bool CanProcessEventsOnApplistViews() override;
-  ws::WindowService* GetWindowService() override;
+  void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) override;
 
   void OnVisibilityChanged(bool visible);
   void OnTargetVisibilityChanged(bool visible);
@@ -224,6 +221,15 @@
   // Performs the 'back' action for the active page.
   void Back();
 
+  // Handles app list button press event. (Search key should trigger the same
+  // behavior.) All three parameters are only used in clamshell mode.
+  // |display_id| is the id of display where app list should toggle.
+  // |show_source| is the source of the event. |event_time_stamp| records the
+  // event timestamp.
+  void OnAppListButtonPressed(int64_t display_id,
+                              app_list::AppListShowSource show_source,
+                              base::TimeTicks event_time_stamp);
+
  private:
   syncer::StringOrdinal GetOemFolderPos();
   std::unique_ptr<app_list::AppListItem> CreateAppListItem(
@@ -239,8 +245,6 @@
 
   int64_t GetDisplayIdToShowAppListOn();
 
-  ws::WindowService* window_service_;
-
   base::string16 last_raw_query_;
 
   mojom::AppListClientPtr client_;
@@ -255,7 +259,9 @@
   // Bindings for the AppListController interface.
   mojo::BindingSet<mojom::AppListController> bindings_;
 
-  // Token to view map for classic/mus ash (i.e. non-mash).
+  // TODO(https://crbug.com/894987): Remove this once assistant UI is converted
+  // to use Content Service, as there will then be no more consumers of
+  // AnswerCardContentsRegistry.
   std::unique_ptr<app_list::AnswerCardContentsRegistry>
       answer_card_contents_registry_;
 
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc
index d0b6a6b..72a5fe1 100644
--- a/ash/app_list/app_list_presenter_delegate_unittest.cc
+++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -101,8 +101,6 @@
   // testing::Test:
   void SetUp() override {
     app_list::AppListView::SetShortAnimationForTesting(true);
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        keyboard::switches::kEnableVirtualKeyboard);
     AshTestBase::SetUp();
 
     // Make the display big enough to hold the app list.
@@ -784,65 +782,6 @@
   GetAppListTestHelper()->CheckVisibility(false);
 }
 
-// Tests that tapping or clicking the body of the applist with an active virtual
-// keyboard results in the virtual keyboard closing with no side effects.
-TEST_P(AppListPresenterDelegateTest,
-       TapAppListWithVirtualKeyboardDismissesVirtualKeyboard) {
-  const bool test_click = GetParam();
-  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
-  EnableTabletMode(true);
-
-  // Tap to activate the searchbox.
-  ui::test::EventGenerator* generator = GetEventGenerator();
-  generator->GestureTapAt(GetPointInsideSearchbox());
-
-  // Enter some text in the searchbox, the applist should transition to
-  // fullscreen search.
-  generator->PressKey(ui::KeyboardCode::VKEY_0, 0);
-  GetAppListTestHelper()->WaitUntilIdle();
-  GetAppListTestHelper()->CheckState(
-      app_list::AppListViewState::FULLSCREEN_SEARCH);
-
-  // Manually show the virtual keyboard.
-  auto* const keyboard_controller = keyboard::KeyboardController::Get();
-  keyboard_controller->ShowKeyboard(true);
-  keyboard_controller->GetKeyboardWindow()->SetBounds(
-      keyboard::KeyboardBoundsFromRootBounds(
-          Shell::GetPrimaryRootWindow()->bounds(), 100));
-  keyboard_controller->NotifyKeyboardWindowLoaded();
-  EXPECT_TRUE(keyboard_controller->IsKeyboardVisible());
-
-  // Tap or click outside the searchbox, the virtual keyboard should hide.
-  if (test_click) {
-    generator->MoveMouseTo(GetPointOutsideSearchbox());
-    generator->ClickLeftButton();
-    generator->ReleaseLeftButton();
-  } else {
-    generator->GestureTapAt(GetPointOutsideSearchbox());
-  }
-  EXPECT_FALSE(keyboard_controller->IsKeyboardVisible());
-
-  // The searchbox should still be active and the AppListView should still be in
-  // FULLSCREEN_SEARCH.
-  GetAppListTestHelper()->WaitUntilIdle();
-  GetAppListTestHelper()->CheckState(
-      app_list::AppListViewState::FULLSCREEN_SEARCH);
-  EXPECT_TRUE(GetAppListView()->search_box_view()->is_search_box_active());
-
-  // Tap or click the body of the AppList again, the searchbox should deactivate
-  // and the applist should be in FULLSCREEN_ALL_APPS.
-  if (test_click) {
-    generator->MoveMouseTo(GetPointOutsideSearchbox());
-    generator->ClickLeftButton();
-    generator->ReleaseLeftButton();
-  } else {
-    generator->GestureTapAt(GetPointOutsideSearchbox());
-  }
-  GetAppListTestHelper()->CheckState(
-      app_list::AppListViewState::FULLSCREEN_ALL_APPS);
-  EXPECT_FALSE(GetAppListView()->search_box_view()->is_search_box_active());
-}
-
 // Tests that the shelf background displays/hides with bottom shelf
 // alignment.
 TEST_F(AppListPresenterDelegateTest,
@@ -1682,4 +1621,80 @@
   EXPECT_EQ(window.get(), wm::GetActiveWindow());
 }
 
+// Tests that involve the virtual keyboard.
+class AppListPresenterDelegateVirtualKeyboardTest
+    : public AppListPresenterDelegateTest {
+ public:
+  AppListPresenterDelegateVirtualKeyboardTest() = default;
+  ~AppListPresenterDelegateVirtualKeyboardTest() override = default;
+
+  // AppListPresenterDelegateTest:
+  void SetUp() override {
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        keyboard::switches::kEnableVirtualKeyboard);
+    AppListPresenterDelegateTest::SetUp();
+  }
+};
+
+// Instantiate the Boolean which is used to toggle mouse and touch events in
+// the parameterized tests.
+INSTANTIATE_TEST_CASE_P(,
+                        AppListPresenterDelegateVirtualKeyboardTest,
+                        testing::Bool());
+
+// Tests that tapping or clicking the body of the applist with an active virtual
+// keyboard results in the virtual keyboard closing with no side effects.
+TEST_P(AppListPresenterDelegateVirtualKeyboardTest,
+       TapAppListWithVirtualKeyboardDismissesVirtualKeyboard) {
+  const bool test_click = GetParam();
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  EnableTabletMode(true);
+
+  // Tap to activate the searchbox.
+  ui::test::EventGenerator* generator = GetEventGenerator();
+  generator->GestureTapAt(GetPointInsideSearchbox());
+
+  // Enter some text in the searchbox, the applist should transition to
+  // fullscreen search.
+  generator->PressKey(ui::KeyboardCode::VKEY_0, 0);
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckState(
+      app_list::AppListViewState::FULLSCREEN_SEARCH);
+
+  // Manually show the virtual keyboard.
+  auto* const keyboard_controller = keyboard::KeyboardController::Get();
+  keyboard_controller->ShowKeyboard(true);
+  ASSERT_TRUE(keyboard::WaitUntilShown());
+
+  // Tap or click outside the searchbox, the virtual keyboard should hide.
+  if (test_click) {
+    generator->MoveMouseTo(GetPointOutsideSearchbox());
+    generator->ClickLeftButton();
+    generator->ReleaseLeftButton();
+  } else {
+    generator->GestureTapAt(GetPointOutsideSearchbox());
+  }
+  EXPECT_FALSE(keyboard_controller->IsKeyboardVisible());
+
+  // The searchbox should still be active and the AppListView should still be in
+  // FULLSCREEN_SEARCH.
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckState(
+      app_list::AppListViewState::FULLSCREEN_SEARCH);
+  EXPECT_TRUE(GetAppListView()->search_box_view()->is_search_box_active());
+
+  // Tap or click the body of the AppList again, the searchbox should deactivate
+  // and the applist should be in FULLSCREEN_ALL_APPS.
+  if (test_click) {
+    generator->MoveMouseTo(GetPointOutsideSearchbox());
+    generator->ClickLeftButton();
+    generator->ReleaseLeftButton();
+  } else {
+    generator->GestureTapAt(GetPointOutsideSearchbox());
+  }
+  GetAppListTestHelper()->CheckState(
+      app_list::AppListViewState::FULLSCREEN_ALL_APPS);
+  EXPECT_FALSE(GetAppListView()->search_box_view()->is_search_box_active());
+}
+
 }  // namespace ash
diff --git a/ash/app_list/app_list_view_delegate.h b/ash/app_list/app_list_view_delegate.h
index 6b851538..18a94b2 100644
--- a/ash/app_list/app_list_view_delegate.h
+++ b/ash/app_list/app_list_view_delegate.h
@@ -12,6 +12,7 @@
 #include "ash/public/interfaces/menu.mojom.h"
 #include "base/callback_forward.h"
 #include "base/strings/string16.h"
+#include "services/content/public/mojom/navigable_contents_factory.mojom.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/events/event_constants.h"
@@ -21,10 +22,6 @@
 class GestureEvent;
 }  // namespace ui
 
-namespace ws {
-class WindowService;
-}  // namespace ws
-
 namespace app_list {
 
 class AppListModel;
@@ -127,7 +124,11 @@
   // its descendants.
   virtual bool CanProcessEventsOnApplistViews() = 0;
 
-  virtual ws::WindowService* GetWindowService() = 0;
+  // Acquires a factory interface from the client which can be used to acquire
+  // initialize new NavigableContents objects for embedding web contents into
+  // the app list UI.
+  virtual void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) = 0;
 };
 
 }  // namespace app_list
diff --git a/ash/app_list/home_launcher_gesture_handler.cc b/ash/app_list/home_launcher_gesture_handler.cc
index e76ac3e..53129af 100644
--- a/ash/app_list/home_launcher_gesture_handler.cc
+++ b/ash/app_list/home_launcher_gesture_handler.cc
@@ -190,6 +190,9 @@
 
 bool HomeLauncherGestureHandler::OnScrollEvent(const gfx::Point& location,
                                                float scroll_y) {
+  if (IsAnimating())
+    return false;
+
   if (!IsDragInProgress())
     return false;
 
@@ -209,11 +212,15 @@
 
 bool HomeLauncherGestureHandler::OnReleaseEvent(const gfx::Point& location,
                                                 bool* out_dragged_down) {
+  if (IsAnimating())
+    return false;
+
   if (!IsDragInProgress()) {
     if (window_) {
       // |window_| may not be nullptr when this release event is triggered by
       // opening |window_| with modal dialog in OnPressEvent(). In that case,
       // just leave the |window_| in show state and stop tracking.
+      AnimateToFinalState();
       RemoveObserversAndStopTracking();
       return true;
     }
@@ -551,26 +558,27 @@
 }
 
 bool HomeLauncherGestureHandler::IsIdle() {
-  if (IsDragInProgress())
-    return false;
+  return !IsDragInProgress() && !IsAnimating();
+}
 
+bool HomeLauncherGestureHandler::IsAnimating() {
   if (window_ && window_->layer()->GetAnimator()->is_animating())
-    return false;
+    return true;
 
   if (window2_ && window2_->layer()->GetAnimator()->is_animating())
-    return false;
+    return true;
 
   for (const auto& descendant : transient_descendants_values_) {
     if (descendant.first->layer()->GetAnimator()->is_animating())
-      return false;
+      return true;
   }
 
   for (const auto& descendant : transient_descendants_values2_) {
     if (descendant.first->layer()->GetAnimator()->is_animating())
-      return false;
+      return true;
   }
 
-  return true;
+  return false;
 }
 
 bool HomeLauncherGestureHandler::IsFinalStateShow() {
diff --git a/ash/app_list/home_launcher_gesture_handler.h b/ash/app_list/home_launcher_gesture_handler.h
index 783eb86..112d6736 100644
--- a/ash/app_list/home_launcher_gesture_handler.h
+++ b/ash/app_list/home_launcher_gesture_handler.h
@@ -115,6 +115,9 @@
   // Returns true if there's no gesture dragging and animation.
   bool IsIdle();
 
+  // Returns true if animation is running.
+  bool IsAnimating();
+
   // Returns true if home launcher should run animation to show. Otherwise,
   // returns false.
   bool IsFinalStateShow();
diff --git a/ash/app_list/model/search/search_model.cc b/ash/app_list/model/search/search_model.cc
index e790813..09c3fe6 100644
--- a/ash/app_list/model/search/search_model.cc
+++ b/ash/app_list/model/search/search_model.cc
@@ -62,12 +62,10 @@
   // Add items back to |results_| in the order of |new_results|.
   for (auto&& new_result : new_results) {
     auto ui_result_it = results_map.find(new_result->id());
-    if (ui_result_it != results_map.end() &&
-        new_result->answer_card_contents_token() ==
-            ui_result_it->second->answer_card_contents_token()) {
+    if (ui_result_it != results_map.end()) {
       // Update and use the old result if it exists.
       std::unique_ptr<SearchResult> ui_result = std::move(ui_result_it->second);
-      ui_result->SetMetadata(new_result->CloneMetadata());
+      ui_result->SetMetadata(new_result->TakeMetadata());
       results_->Add(std::move(ui_result));
 
       // Remove the item from the map so that it ends up only with unused
@@ -90,6 +88,15 @@
   return nullptr;
 }
 
+SearchResult* SearchModel::GetFirstVisibleResult() {
+  for (const auto& result : *results_) {
+    if (result->is_visible())
+      return result.get();
+  }
+
+  return nullptr;
+}
+
 void SearchModel::DeleteAllResults() {
   PublishResults(std::vector<std::unique_ptr<SearchResult>>());
 }
diff --git a/ash/app_list/model/search/search_model.h b/ash/app_list/model/search/search_model.h
index 4a78c68..f4b0720 100644
--- a/ash/app_list/model/search/search_model.h
+++ b/ash/app_list/model/search/search_model.h
@@ -54,6 +54,10 @@
 
   SearchResult* FindSearchResult(const std::string& id);
 
+  // Returns the first available SearchResult which has not been marked as
+  // hidden by its source. Returns null if no such result exists.
+  SearchResult* GetFirstVisibleResult();
+
   // Deletes all search results. This is used in profile switches.
   void DeleteAllResults();
 
diff --git a/ash/app_list/model/search/search_result.h b/ash/app_list/model/search/search_result.h
index 621a2ac..9a3acae 100644
--- a/ash/app_list/model/search/search_result.h
+++ b/ash/app_list/model/search/search_result.h
@@ -80,18 +80,8 @@
   }
   void SetFormattedPrice(const base::string16& formatted_price);
 
-  const base::Optional<base::UnguessableToken>& answer_card_contents_token()
-      const {
-    return metadata_->answer_card_contents_token;
-  }
-  void set_answer_card_contents_token(
-      const base::Optional<base::UnguessableToken>& token) {
-    metadata_->answer_card_contents_token = token;
-  }
-
-  gfx::Size answer_card_size() const {
-    return metadata_->answer_card_size.value_or(gfx::Size());
-  }
+  const base::Optional<GURL>& query_url() const { return metadata_->query_url; }
+  void set_query_url(const GURL& url) { metadata_->query_url = url; }
 
   const std::string& id() const { return metadata_->id; }
 
@@ -129,6 +119,9 @@
     metadata_->is_omnibox_search = is_omnibox_search;
   }
 
+  bool is_visible() const { return is_visible_; }
+  void set_is_visible(bool is_visible) { is_visible_ = is_visible; }
+
   void NotifyItemInstalled();
 
   void AddObserver(SearchResultObserver* observer);
@@ -138,8 +131,8 @@
   virtual void InvokeAction(int action_index, int event_flags);
 
   void SetMetadata(ash::mojom::SearchResultMetadataPtr metadata);
-  ash::mojom::SearchResultMetadataPtr CloneMetadata() const {
-    return metadata_.Clone();
+  ash::mojom::SearchResultMetadataPtr TakeMetadata() {
+    return std::move(metadata_);
   }
 
  protected:
@@ -157,6 +150,7 @@
 
   bool is_installing_ = false;
   int percent_downloaded_ = 0;
+  bool is_visible_ = true;
 
   ash::mojom::SearchResultMetadataPtr metadata_;
 
diff --git a/ash/app_list/paged_view_structure.cc b/ash/app_list/paged_view_structure.cc
index 13a99b7..e6570a0 100644
--- a/ash/app_list/paged_view_structure.cc
+++ b/ash/app_list/paged_view_structure.cc
@@ -94,9 +94,14 @@
 
     if (item_index < item_list->item_count() &&
         !item_list->item_at(item_index)->is_page_break()) {
+      // Remove AppListItemListObserver temporarily to avoid |pages_| being
+      // reloaded.
+      item_list->RemoveObserver(apps_grid_view_);
+
       // There's no "page break" item at the end of current page, so add one to
       // push overflowing items to next page.
       model->AddPageBreakItemAfter(item_list->item_at(item_index - 1));
+      item_list->AddObserver(apps_grid_view_);
     }
   }
 
diff --git a/ash/app_list/presenter/app_list_presenter_impl.cc b/ash/app_list/presenter/app_list_presenter_impl.cc
index 8f8adf5..e012041 100644
--- a/ash/app_list/presenter/app_list_presenter_impl.cc
+++ b/ash/app_list/presenter/app_list_presenter_impl.cc
@@ -243,6 +243,9 @@
   }
   layer->SetOpacity(opacity);
   layer->SetTransform(translation);
+
+  // Update child views' y positions to target state to avoid stale positions.
+  view_->app_list_main_view()->contents_view()->UpdateYPositionAndOpacity();
 }
 
 void AppListPresenterImpl::ScheduleOverviewModeAnimation(bool start,
diff --git a/ash/app_list/test/app_list_test_view_delegate.cc b/ash/app_list/test/app_list_test_view_delegate.cc
index ec9b38e..06949e0 100644
--- a/ash/app_list/test/app_list_test_view_delegate.cc
+++ b/ash/app_list/test/app_list_test_view_delegate.cc
@@ -98,8 +98,9 @@
   return true;
 }
 
-ws::WindowService* AppListTestViewDelegate::GetWindowService() {
-  return nullptr;
+void AppListTestViewDelegate::GetNavigableContentsFactory(
+    content::mojom::NavigableContentsFactoryRequest request) {
+  fake_navigable_contents_factory_.BindRequest(std::move(request));
 }
 
 void AppListTestViewDelegate::GetSearchResultContextMenuModel(
diff --git a/ash/app_list/test/app_list_test_view_delegate.h b/ash/app_list/test/app_list_test_view_delegate.h
index 88333b5..7144f60 100644
--- a/ash/app_list/test/app_list_test_view_delegate.h
+++ b/ash/app_list/test/app_list_test_view_delegate.h
@@ -18,6 +18,7 @@
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "services/content/public/cpp/test/fake_navigable_contents_factory.h"
 #include "ui/base/models/simple_menu_model.h"
 
 namespace app_list {
@@ -45,6 +46,10 @@
   // SetProfileByPath() is called.
   void set_next_profile_app_count(int apps) { next_profile_app_count_ = apps; }
 
+  content::FakeNavigableContentsFactory& fake_navigable_contents_factory() {
+    return fake_navigable_contents_factory_;
+  }
+
   // Sets whether the search engine is Google or not.
   void SetSearchEngineIsGoogle(bool is_google);
 
@@ -80,7 +85,8 @@
   bool ProcessHomeLauncherGesture(ui::GestureEvent* event,
                                   const gfx::Point& screen_location) override;
   bool CanProcessEventsOnApplistViews() override;
-  ws::WindowService* GetWindowService() override;
+  void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) override;
 
   // Do a bulk replacement of the items in the model.
   void ReplaceTestModel(int item_count);
@@ -103,6 +109,7 @@
   std::unique_ptr<SearchModel> search_model_;
   std::vector<SkColor> wallpaper_prominent_colors_;
   ui::SimpleMenuModel search_result_context_menu_model_;
+  content::FakeNavigableContentsFactory fake_navigable_contents_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListTestViewDelegate);
 };
diff --git a/ash/app_list/test/test_app_list_client.h b/ash/app_list/test/test_app_list_client.h
index 8727252..10a24a0 100644
--- a/ash/app_list/test/test_app_list_client.h
+++ b/ash/app_list/test/test_app_list_client.h
@@ -45,14 +45,16 @@
                                int event_flags) override {}
   void OnAppListTargetVisibilityChanged(bool visible) override {}
   void OnAppListVisibilityChanged(bool visible) override {}
-  void StartVoiceInteractionSession() override;
-  void ToggleVoiceInteractionSession() override;
   void OnFolderCreated(mojom::AppListItemMetadataPtr item) override {}
   void OnFolderDeleted(mojom::AppListItemMetadataPtr item) override {}
   void OnItemUpdated(mojom::AppListItemMetadataPtr item) override {}
   void OnPageBreakItemAdded(const std::string& id,
                             const syncer::StringOrdinal& position) override {}
   void OnPageBreakItemDeleted(const std::string& id) override {}
+  void StartVoiceInteractionSession() override;
+  void ToggleVoiceInteractionSession() override;
+  void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) override {}
 
   size_t voice_session_count() const { return voice_session_count_; }
 
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index 039a8a3..e183387 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -446,6 +446,7 @@
     const gfx::Point& point,
     ui::MenuSourceType source_type,
     std::vector<ash::mojom::MenuItemPtr> menu) {
+  waiting_for_context_menu_options_ = false;
   if (menu.empty() || (context_menu_ && context_menu_->IsShowingMenu()))
     return;
 
@@ -490,6 +491,13 @@
 void AppListItemView::ShowContextMenuForView(views::View* source,
                                              const gfx::Point& point,
                                              ui::MenuSourceType source_type) {
+  // Prevent multiple requests for context menus before the current request
+  // completes. If a second request is sent before the first one can respond,
+  // the Chrome side delegate will become unresponsive
+  // (https://crbug.com/881886).
+  if (waiting_for_context_menu_options_)
+    return;
+  waiting_for_context_menu_options_ = true;
   delegate_->GetContextMenuModel(
       item_weak_->id(),
       base::BindOnce(&AppListItemView::OnContextMenuModelReceived,
@@ -648,6 +656,12 @@
   return true;
 }
 
+bool AppListItemView::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
+  // Ensure accelerators take priority in the app list. This ensures, e.g., that
+  // Ctrl+Space will switch input methods rather than activate the button.
+  return false;
+}
+
 void AppListItemView::OnFocus() {
   apps_grid_view_->SetSelectedView(this);
 }
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h
index fdf2997..6586ef0 100644
--- a/ash/app_list/views/app_list_item_view.h
+++ b/ash/app_list/views/app_list_item_view.h
@@ -198,6 +198,7 @@
   bool OnMousePressed(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
   bool OnMouseDragged(const ui::MouseEvent& event) override;
+  bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override;
   void OnFocus() override;
   void OnBlur() override;
 
@@ -223,6 +224,10 @@
   const bool is_folder_;
   const bool is_in_folder_;
 
+  // Whether context menu options have been requested. Prevents multiple
+  // requests.
+  bool waiting_for_context_menu_options_ = false;
+
   AppListItem* item_weak_;  // Owned by AppListModel. Can be NULL.
 
   AppListViewDelegate* delegate_;            // Unowned.
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 88ff037..39c06c6 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -97,7 +97,7 @@
 constexpr int kAppListHomeLaucherGesturesThreshold = 32;
 
 // Quality of the shield background blur.
-constexpr float kAppListBlurQuality = 0.25f;
+constexpr float kAppListBlurQuality = 0.33f;
 
 // Set animation durations to 0 for testing.
 static bool short_animations_for_testing;
@@ -1260,9 +1260,9 @@
   layer->SetTransform(gfx::Transform());
 
   // In transition animation, layout is only performed after it is complete,
-  // which makes the child views jump. So layout in advance here to avoid that.
-  GetAppsContainerView()->InvalidateLayout();
-  Layout();
+  // which makes the child views jump. So update y positions in advance here to
+  // avoid that.
+  app_list_main_view_->contents_view()->UpdateYPositionAndOpacity();
 }
 
 void AppListView::StartCloseAnimation(base::TimeDelta animation_duration) {
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc
index 59c5dfa..c790602 100644
--- a/ash/app_list/views/app_list_view_unittest.cc
+++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -37,7 +37,6 @@
 #include "ash/app_list/views/suggestion_chip_view.h"
 #include "ash/app_list/views/suggestions_container_view.h"
 #include "ash/app_list/views/test/apps_grid_view_test_api.h"
-#include "ash/public/cpp/app_list/answer_card_contents_registry.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
@@ -47,6 +46,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/icu_test_util.h"
 #include "base/test/scoped_feature_list.h"
+#include "services/content/public/cpp/test/fake_navigable_contents.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/chromeos/search_box/search_box_constants.h"
@@ -278,14 +278,11 @@
     }
 
     views::ViewsTestBase::SetUp();
-    answer_card_contents_registry_ =
-        std::make_unique<AnswerCardContentsRegistry>();
-    fake_answer_card_view_ = std::make_unique<views::View>();
-    fake_answer_card_view_->set_owned_by_client();
-    fake_answer_card_token_ = answer_card_contents_registry_->Register(
-        fake_answer_card_view_.get(), /*contents_native_view=*/nullptr);
 
     // Initialize app list view.
+    fake_card_contents_.set_default_response_headers(
+        SearchResultAnswerCardView::CreateAnswerCardResponseHeadersForTest(
+            "weather", "Unimportant Title"));
     delegate_ = std::make_unique<AppListTestViewDelegate>();
     view_ = new AppListView(delegate_.get());
     AppListView::InitParams params;
@@ -325,6 +322,10 @@
     // Disable animation timer.
     view_->GetWidget()->GetLayer()->GetAnimator()->set_disable_timer_for_test(
         true);
+
+    // The Update above will elicit a navigation. Wait for it.
+    delegate_->fake_navigable_contents_factory()
+        .WaitForAndBindNextContentsRequest(&fake_card_contents_);
   }
 
   void TearDown() override {
@@ -379,8 +380,10 @@
             std::make_unique<TestSearchResult>();
         result->set_display_type(data.first);
         result->set_display_score(display_score);
-        if (data.first == ash::SearchResultDisplayType::kCard)
-          result->set_answer_card_contents_token(fake_answer_card_token_);
+        if (data.first == ash::SearchResultDisplayType::kCard) {
+          const GURL kFakeCardUrl = GURL("https://www.google.com/coac?q=fake");
+          result->set_query_url(kFakeCardUrl);
+        }
         results->Add(std::move(result));
       }
     }
@@ -592,13 +595,12 @@
   // Restores the locale to default when destructor is called.
   base::test::ScopedRestoreICUDefaultLocale restore_locale_;
 
-  std::unique_ptr<AnswerCardContentsRegistry> answer_card_contents_registry_;
-  std::unique_ptr<views::View> fake_answer_card_view_;
-  base::UnguessableToken fake_answer_card_token_;
-
   // Used by AppListFolderView::UpdatePreferredBounds.
   keyboard::KeyboardController keyboard_controller_;
 
+  // A fake NavigableContents implementation to back card navigation requests.
+  content::FakeNavigableContents fake_card_contents_;
+
   DISALLOW_COPY_AND_ASSIGN(AppListViewFocusTest);
 };
 
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index 34243e8..08a1cf6 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -470,6 +470,9 @@
     if (item_view->item()->is_folder())
       item_view->SetBackgroundBlurEnabled(started);
   }
+
+  // Prevent context menus from remaining open after a transition
+  CancelContextMenusOnCurrentPage();
 }
 
 void AppsGridView::SetModel(AppListModel* model) {
@@ -963,9 +966,11 @@
     } else {
       // TODO(newcomer): Improve implementation of the mask layer so we can
       // enable it on all devices https://crbug.com/765292.
-      if (!fadeout_layer_delegate_)
-        fadeout_layer_delegate_ = std::make_unique<FadeoutLayerDelegate>();
       if (!layer()->layer_mask_layer()) {
+        // Always create a new layer. The layer may be recreated by animation,
+        // and using the mask layer used by the detached layer can lead to
+        // crash. b/118822974.
+        fadeout_layer_delegate_ = std::make_unique<FadeoutLayerDelegate>();
         layer()->SetMaskLayer(fadeout_layer_delegate_->layer());
         fadeout_layer_delegate_->layer()->SetBounds(layer()->bounds());
       }
@@ -1945,9 +1950,11 @@
   // changes from 0.f to 1.0f.
   const float peeking_to_fullscreen_height =
       app_list_view->GetFullscreenStateHeight() - peeking_height;
-  DCHECK_GT(peeking_to_fullscreen_height, 0);
   const float drag_amount = current_height - peeking_height;
-  fraction = std::max(drag_amount / peeking_to_fullscreen_height, 0.f);
+  fraction = std::max(peeking_to_fullscreen_height > 0
+                          ? drag_amount / peeking_to_fullscreen_height
+                          : 1.0f,
+                      0.f);
   opacity = std::min(std::max((fraction + kAllAppsIndicatorOpacityEndFraction -
                                kAllAppsIndicatorOpacityStartFraction - 1.0f) /
                                   (kAllAppsIndicatorOpacityEndFraction -
@@ -2461,6 +2468,8 @@
 
 void AppsGridView::CancelContextMenusOnCurrentPage() {
   GridIndex start_index(pagination_model_.selected_page(), 0);
+  if (!IsValidIndex(start_index))
+    return;
   int start = GetModelIndexFromIndex(start_index);
   int end =
       std::min(view_model_.view_size(), start + TilesPerPage(start_index.page));
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index b71cb2b..a4ba681c 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -288,12 +288,12 @@
 void SearchBoxView::UpdateLayout(double progress,
                                  ash::AppListState current_state,
                                  ash::AppListState target_state) {
+  const int horizontal_spacing = gfx::Tween::LinearIntValueBetween(
+      progress, GetBoxLayoutPaddingForState(current_state),
+      GetBoxLayoutPaddingForState(target_state));
   box_layout()->set_inside_border_insets(
-      gfx::Insets(0,
-                  gfx::Tween::LinearIntValueBetween(
-                      progress, GetBoxLayoutPaddingForState(current_state),
-                      GetBoxLayoutPaddingForState(target_state)),
-                  0, 0));
+      gfx::Insets(0, horizontal_spacing, 0, 0));
+  box_layout()->set_between_child_spacing(horizontal_spacing);
   if (show_assistant_button()) {
     assistant_button()->layer()->SetOpacity(gfx::Tween::LinearIntValueBetween(
         progress, GetAssistantButtonOpacityForState(current_state),
@@ -365,24 +365,24 @@
   if (!is_app_list_search_autocomplete_enabled_)
     return;
 
+  SearchResult* const first_visible_result =
+      search_model_->GetFirstVisibleResult();
+
   // Current non-autocompleted text.
   const base::string16& user_typed_text =
       search_box()->text().substr(0, highlight_range_.start());
   if (last_key_pressed_ == ui::VKEY_BACK || last_key_pressed_ == ui::VKEY_UP ||
       last_key_pressed_ == ui::VKEY_DOWN ||
       last_key_pressed_ == ui::VKEY_LEFT ||
-      last_key_pressed_ == ui::VKEY_RIGHT ||
-      search_model_->results()->item_count() == 0 ||
+      last_key_pressed_ == ui::VKEY_RIGHT || !first_visible_result ||
       user_typed_text.length() < kMinimumLengthToAutocomplete) {
     // Backspace or arrow keys were pressed, no results exist, or current text
     // is too short for a confident autocomplete suggestion.
     return;
   }
 
-  const base::string16& details =
-      search_model_->results()->GetItemAt(0)->details();
-  const base::string16& search_text =
-      search_model_->results()->GetItemAt(0)->title();
+  const base::string16& details = first_visible_result->details();
+  const base::string16& search_text = first_visible_result->title();
   if (base::StartsWith(details, user_typed_text,
                        base::CompareCase::INSENSITIVE_ASCII)) {
     // Current text in the search_box matches the first result's url.
diff --git a/ash/app_list/views/search_result_answer_card_view.cc b/ash/app_list/views/search_result_answer_card_view.cc
index 98ca4da..4beb79b 100644
--- a/ash/app_list/views/search_result_answer_card_view.cc
+++ b/ash/app_list/views/search_result_answer_card_view.cc
@@ -12,16 +12,23 @@
 #include "ash/app_list/app_list_view_delegate.h"
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/app_list/views/search_result_base_view.h"
-#include "ash/public/cpp/app_list/answer_card_contents_registry.h"
 #include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/bind.h"
-#include "base/feature_list.h"
-#include "services/ws/public/mojom/window_tree.mojom.h"
-#include "services/ws/remote_view_host/server_remote_view_host.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
+#include "base/optional.h"
+#include "base/strings/strcat.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "services/content/public/cpp/navigable_contents.h"
+#include "services/content/public/cpp/navigable_contents_view.h"
+#include "services/content/public/mojom/navigable_contents_factory.mojom.h"
 #include "ui/accessibility/ax_node.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/aura/window.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/background.h"
 #include "ui/views/layout/box_layout.h"
@@ -31,45 +38,9 @@
 
 namespace {
 
-// Holds answer card data. |view| is the view to be added to app list view
-// hierarchy. |native_view| is the root of the card contents view. For classic
-// ash, it is the NativeView of the answer card WebContents. For mash, it is
-// the embedding root for answer card contents.
-struct CardData {
-  views::View* view = nullptr;
-  gfx::NativeView native_view = nullptr;
-};
-
-// Get answer card data by token.
-CardData GetCardDataByToken(
-    ws::WindowService* window_service,
-    const base::Optional<base::UnguessableToken>& token) {
-  // Bail for invalid token.
-  if (!token.has_value() || token->is_empty())
-    return {};
-
-  // Use AnswerCardContentsRegistry for an in-process token-to-view map. See
-  // answer_card_contents_registry.h. Null check because it could be missing in
-  // Mash and for tests.
-  auto* card_registry = AnswerCardContentsRegistry::Get();
-  if (card_registry) {
-    return {card_registry->GetView(token.value()),
-            card_registry->GetNativeView(token.value())};
-  }
-
-  // Use ServerRemoteViewHost to embed the answer card contents provided in the
-  // browser process in Mash.
-  if (features::IsUsingWindowService()) {
-    ws::ServerRemoteViewHost* view =
-        new ws::ServerRemoteViewHost(window_service);
-    view->EmbedUsingToken(token.value(),
-                          ws::mojom::kEmbedFlagEmbedderControlsVisibility,
-                          base::DoNothing());
-    return {view, view->embedding_root()};
-  }
-
-  return {};
-}
+constexpr char kSearchAnswerHasResult[] = "SearchAnswer-HasResult";
+constexpr char kSearchAnswerIssuedQuery[] = "SearchAnswer-IssuedQuery";
+constexpr char kSearchAnswerTitle[] = "SearchAnswer-Title";
 
 // Exclude the card native view from event handling.
 void ExcludeCardFromEventHandling(gfx::NativeView card_native_view) {
@@ -78,7 +49,7 @@
     return;
 
   if (!card_native_view->parent()) {
-    LOG(ERROR) << "Card is not attached to the app list view.";
+    DLOG(ERROR) << "Card is not attached to the app list view.";
     return;
   }
 
@@ -97,14 +68,43 @@
   AppListView::ExcludeWindowFromEventHandling(window);
 }
 
+bool ParseResponseHeaders(const net::HttpResponseHeaders* headers,
+                          std::string* title,
+                          std::string* issued_query) {
+  if (!headers || headers->response_code() != net::HTTP_OK)
+    return false;
+
+  if (!headers->HasHeaderValue(kSearchAnswerHasResult, "true")) {
+    DLOG(WARNING) << "Response not an answer card. Expected a value of \"true\""
+                  << " for " << kSearchAnswerHasResult << " header.";
+    return false;
+  }
+  if (!headers->GetNormalizedHeader(kSearchAnswerTitle, title) ||
+      title->empty()) {
+    DLOG(WARNING) << "Ignoring answer card response with no valid "
+                  << kSearchAnswerTitle << " header present.";
+    return false;
+  }
+  if (!headers->GetNormalizedHeader(kSearchAnswerIssuedQuery, issued_query) ||
+      issued_query->empty()) {
+    DLOG(WARNING) << "Ignoring answer card response with no valid "
+                  << kSearchAnswerIssuedQuery << " header present.";
+    return false;
+  }
+
+  return true;
+}
+
 }  // namespace
 
 // Container of the search answer view.
 class SearchResultAnswerCardView::SearchAnswerContainerView
-    : public SearchResultBaseView {
+    : public SearchResultBaseView,
+      public content::NavigableContentsObserver {
  public:
-  explicit SearchAnswerContainerView(AppListViewDelegate* view_delegate)
-      : view_delegate_(view_delegate) {
+  SearchAnswerContainerView(SearchResultContainerView* container,
+                            AppListViewDelegate* view_delegate)
+      : container_(container), view_delegate_(view_delegate) {
     SetFocusBehavior(FocusBehavior::ALWAYS);
     // Center the card horizontally in the container. Padding is set on the
     // server.
@@ -113,52 +113,80 @@
     answer_container_layout->set_main_axis_alignment(
         views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
     SetLayoutManager(std::move(answer_container_layout));
+
+    view_delegate_->GetNavigableContentsFactory(
+        mojo::MakeRequest(&contents_factory_));
+
+    auto params = content::mojom::NavigableContentsParams::New();
+    params->enable_view_auto_resize = true;
+    params->suppress_navigations = true;
+    contents_ = std::make_unique<content::NavigableContents>(
+        contents_factory_.get(), std::move(params));
+    contents_->AddObserver(this);
   }
 
   ~SearchAnswerContainerView() override {
+    contents_->RemoveObserver(this);
     if (search_result_)
       search_result_->RemoveObserver(this);
   }
 
-  bool SetSearchResult(SearchResult* search_result) {
-    const base::Optional<base::UnguessableToken> old_token =
-        search_result_ ? search_result_->answer_card_contents_token()
-                       : base::nullopt;
-    const base::Optional<base::UnguessableToken> new_token =
-        search_result ? search_result->answer_card_contents_token()
-                      : base::nullopt;
+  bool has_valid_answer_card() const {
+    return is_current_navigation_valid_answer_card_;
+  }
 
-    views::View* result_view = child_count() ? child_at(0) : nullptr;
-    if (old_token != new_token) {
-      RemoveAllChildViews(true /* delete_children */);
+  void HideCard() {
+    OnVisibilityChanged(false /* is_visible */);
+    RemoveAllChildViews(false /* delete_children */);
+    SetPreferredSize(gfx::Size{0, 0});
 
-      const CardData card_data =
-          GetCardDataByToken(view_delegate_->GetWindowService(), new_token);
+    // Force any future result changes to initiate another navigation.
+    is_current_navigation_valid_answer_card_ = false;
+  }
 
-      result_view = card_data.view;
-      if (result_view) {
-        AddChildView(result_view);
-        ExcludeCardFromEventHandling(card_data.native_view);
-      }
-    }
-
-    base::string16 old_title;
-    base::string16 new_title;
+  void SetSearchResult(SearchResult* search_result) {
+    // Remove the card contents from the UI temporarily while we attempt to
+    // navigate it to the new query URL.
+    base::Optional<GURL> previous_url;
     if (search_result_) {
+      previous_url = search_result_->query_url();
       search_result_->RemoveObserver(this);
-      old_title = search_result_->title();
+      search_result_ = nullptr;
     }
+
+    if (!search_result || !search_result->query_url()) {
+      HideCard();
+      return;
+    }
+
     search_result_ = search_result;
-    if (search_result_) {
-      search_result_->AddObserver(this);
-      if (result_view)
-        result_view->SetPreferredSize(search_result_->answer_card_size());
+    search_result_->AddObserver(this);
 
-      new_title = search_result_->title();
-      SetAccessibleName(new_title);
+    if (search_result_->query_url() == previous_url &&
+        is_current_navigation_valid_answer_card_) {
+      // The new search result is for a query URL identical to the previous one,
+      // so we don't bother hiding or navigating the existing card contents.
+      return;
     }
 
-    return old_title != new_title;
+    // We hide the view while navigating its contents. Once navigation is
+    // finished and we (possibly) have a valid answer card response, the
+    // contents view will be re-parented to this container.
+    HideCard();
+
+    base::RecordAction(base::UserMetricsAction("SearchAnswer_UserInteraction"));
+
+    contents_->Navigate(*search_result_->query_url());
+  }
+
+  void OnVisibilityChanged(bool is_visible) {
+    if (is_visible && !last_shown_time_) {
+      last_shown_time_ = base::Time::Now();
+    } else if (last_shown_time_) {
+      UMA_HISTOGRAM_MEDIUM_TIMES("SearchAnswer.AnswerVisibleTime",
+                                 base::Time::Now() - *last_shown_time_);
+      last_shown_time_.reset();
+    }
   }
 
   // views::Button overrides:
@@ -207,13 +235,83 @@
 
   // SearchResultObserver overrides:
   void OnResultDestroying() override {
-    RemoveAllChildViews(true /* delete_children */);
+    HideCard();
     search_result_ = nullptr;
   }
 
  private:
-  AppListViewDelegate* const view_delegate_;  // Not owned.
-  SearchResult* search_result_ = nullptr;     // Not owned.
+  // content::NavigableContentsObserver overrides:
+  void DidFinishNavigation(
+      const GURL& url,
+      bool is_main_frame,
+      bool is_error_page,
+      const net::HttpResponseHeaders* response_headers) override {
+    if (!is_main_frame)
+      return;
+
+    is_current_navigation_valid_answer_card_ = false;
+    if (is_error_page)
+      return;
+
+    std::string title;
+    if (!ParseResponseHeaders(response_headers, &title, &answer_card_query_))
+      return;
+
+    SetAccessibleName(base::UTF8ToUTF16(title));
+
+    // TODO(https://crbug.com/894893): Consider where, how to record some
+    // SearchAnswer metrics regarding navigation results and timing.
+
+    is_current_navigation_valid_answer_card_ = true;
+    answer_card_url_ = url;
+  }
+
+  void DidStopLoading() override {
+    if (!is_current_navigation_valid_answer_card_)
+      return;
+
+    OnVisibilityChanged(true /* is_visible */);
+    views::View* content_view = contents_->GetView()->view();
+    if (!has_children()) {
+      AddChildView(content_view);
+      ExcludeCardFromEventHandling(contents_->GetView()->native_view());
+    }
+    SetPreferredSize(content_view->GetPreferredSize());
+    container_->Update();
+  }
+
+  void DidAutoResizeView(const gfx::Size& new_size) override {
+    SetPreferredSize(new_size);
+    contents_->GetView()->view()->SetPreferredSize(new_size);
+    container_->Update();
+  }
+
+  void DidSuppressNavigation(const GURL& url,
+                             WindowOpenDisposition disposition,
+                             bool from_user_gesture) override {
+    if (!from_user_gesture)
+      return;
+
+    // NOTE: We shouldn't ever hit this path since all user gestures targeting
+    // the content area should be intercepted by the Button which overlaps its
+    // display region, and answer cards are generally not expected to elicit
+    // scripted navigations. This action is recorded here to verify these
+    // expectations.
+    base::RecordAction(base::UserMetricsAction("SearchAnswer_OpenedUrl"));
+  }
+
+  SearchResultContainerView* const container_;  // Not owned.
+  AppListViewDelegate* const view_delegate_;    // Not owned.
+  SearchResult* search_result_ = nullptr;       // Not owned.
+  content::mojom::NavigableContentsFactoryPtr contents_factory_;
+  std::unique_ptr<content::NavigableContents> contents_;
+
+  bool is_current_navigation_valid_answer_card_ = false;
+  GURL answer_card_url_;
+  std::string answer_card_query_;
+
+  // Tracks the last time this view was made visible, if still visible.
+  base::Optional<base::Time> last_shown_time_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchAnswerContainerView);
 };
@@ -221,7 +319,7 @@
 SearchResultAnswerCardView::SearchResultAnswerCardView(
     AppListViewDelegate* view_delegate)
     : search_answer_container_view_(
-          new SearchAnswerContainerView(view_delegate)) {
+          new SearchAnswerContainerView(this, view_delegate)) {
   AddChildView(search_answer_container_view_);
   SetLayoutManager(std::make_unique<views::FillLayout>());
 }
@@ -240,20 +338,20 @@
   std::vector<SearchResult*> display_results =
       SearchModel::FilterSearchResultsByDisplayType(
           results(), ash::SearchResultDisplayType::kCard, /*excludes=*/{}, 1);
+  SearchResult* top_result =
+      display_results.empty() ? nullptr : display_results.front();
 
-  const bool have_result = !display_results.empty();
+  const bool has_valid_answer_card =
+      search_answer_container_view_->has_valid_answer_card();
+  search_answer_container_view_->SetSearchResult(top_result);
+  parent()->SetVisible(has_valid_answer_card);
 
-  const bool title_changed = search_answer_container_view_->SetSearchResult(
-      have_result ? display_results[0] : nullptr);
-  parent()->SetVisible(have_result);
+  set_container_score(
+      has_valid_answer_card && top_result ? top_result->display_score() : 0);
+  if (top_result)
+    top_result->set_is_visible(has_valid_answer_card);
 
-  set_container_score(have_result ? display_results.front()->display_score()
-                                  : 0);
-  if (title_changed && search_answer_container_view_->HasFocus()) {
-    search_answer_container_view_->NotifyAccessibilityEvent(
-        ax::mojom::Event::kSelection, true);
-  }
-  return have_result ? 1 : 0;
+  return has_valid_answer_card ? 1 : 0;
 }
 
 bool SearchResultAnswerCardView::OnKeyPressed(const ui::KeyEvent& event) {
@@ -272,4 +370,18 @@
   return search_answer_container_view_;
 }
 
+// static
+scoped_refptr<net::HttpResponseHeaders>
+SearchResultAnswerCardView::CreateAnswerCardResponseHeadersForTest(
+    const std::string& query,
+    const std::string& title) {
+  auto headers =
+      base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
+  headers->AddHeader(base::StrCat({kSearchAnswerHasResult, ": true"}));
+  headers->AddHeader(base::StrCat({kSearchAnswerTitle, ": ", title.c_str()}));
+  headers->AddHeader(
+      base::StrCat({kSearchAnswerIssuedQuery, ": ", query.c_str()}));
+  return headers;
+}
+
 }  // namespace app_list
diff --git a/ash/app_list/views/search_result_answer_card_view.h b/ash/app_list/views/search_result_answer_card_view.h
index 1a3dee4..a208d06 100644
--- a/ash/app_list/views/search_result_answer_card_view.h
+++ b/ash/app_list/views/search_result_answer_card_view.h
@@ -6,6 +6,9 @@
 #define ASH_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_
 
 #include "ash/app_list/views/search_result_container_view.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
+#include "net/http/http_response_headers.h"
 
 namespace app_list {
 
@@ -30,6 +33,10 @@
 
   views::View* GetSearchAnswerContainerViewForTest() const;
 
+  static scoped_refptr<net::HttpResponseHeaders>
+  CreateAnswerCardResponseHeadersForTest(const std::string& query,
+                                         const std::string& title);
+
  private:
   class SearchAnswerContainerView;
 
@@ -37,6 +44,10 @@
   // It's visible iff we have a search answer result.
   SearchAnswerContainerView* const search_answer_container_view_;
 
+  // Tracks the last known card title so we can update the accessibility
+  // framework if the title changes while the card has focus.
+  base::string16 last_known_card_title_;
+
   DISALLOW_COPY_AND_ASSIGN(SearchResultAnswerCardView);
 };
 
diff --git a/ash/app_list/views/search_result_answer_card_view_unittest.cc b/ash/app_list/views/search_result_answer_card_view_unittest.cc
index 876f54e..053199dc 100644
--- a/ash/app_list/views/search_result_answer_card_view_unittest.cc
+++ b/ash/app_list/views/search_result_answer_card_view_unittest.cc
@@ -10,11 +10,12 @@
 #include "ash/app_list/test/app_list_test_view_delegate.h"
 #include "ash/app_list/test/test_search_result.h"
 #include "ash/app_list/views/search_result_view.h"
-#include "ash/public/cpp/app_list/answer_card_contents_registry.h"
 #include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/unguessable_token.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/content/public/cpp/test/fake_navigable_contents.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/views/background.h"
 #include "ui/views/test/views_test_base.h"
@@ -37,31 +38,33 @@
 
     search_card_view_ = std::make_unique<views::View>();
 
+    fake_card_contents_.set_default_response_headers(
+        SearchResultAnswerCardView::CreateAnswerCardResponseHeadersForTest(
+            "weather", kResultTitle));
+
     result_container_view_ = new SearchResultAnswerCardView(&view_delegate_);
     search_card_view_->AddChildView(result_container_view_);
     result_container_view_->SetResults(
         view_delegate_.GetSearchModel()->results());
 
-    result_view_ = std::make_unique<views::View>();
-    result_view_->set_owned_by_client();
-    token_ = contents_registry_.Register(result_view_.get(),
-                                         /*contents_native_view=*/nullptr);
-
     SetUpSearchResult();
   }
 
  protected:
   void SetUpSearchResult() {
+    const GURL kFakeQueryUrl = GURL("https://www.google.com/coac?q=fake");
     SearchModel::SearchResults* results = GetResults();
     std::unique_ptr<TestSearchResult> result =
         std::make_unique<TestSearchResult>();
     result->set_display_type(ash::SearchResultDisplayType::kCard);
     result->set_title(base::UTF8ToUTF16(kResultTitle));
-    result->set_answer_card_contents_token(token_);
     result->set_display_score(kDisplayScore);
+    result->set_query_url(kFakeQueryUrl);
     results->Add(std::move(result));
 
     // Adding results will schedule Update().
+    view_delegate_.fake_navigable_contents_factory()
+        .WaitForAndBindNextContentsRequest(&fake_card_contents_);
     RunPendingMessages();
   }
 
@@ -100,8 +103,6 @@
     result_container_view_->child_at(0)->GetAccessibleNodeData(node_data);
   }
 
-  views::View* result_view() const { return result_view_.get(); }
-
  private:
   AppListTestViewDelegate view_delegate_;
 
@@ -111,25 +112,17 @@
   // Result container that we are testing. It's a child of search_card_view_.
   // Owned by the view hierarchy.
   SearchResultAnswerCardView* result_container_view_;
-  // View sent within the search result. May be shown within
-  // result_container_view_. Has set_owned_by_client() called.
-  std::unique_ptr<views::View> result_view_;
 
-  AnswerCardContentsRegistry contents_registry_;
-  base::UnguessableToken token_;
+  // Fake NavigableContents implementation to back answer card navigations.
+  content::FakeNavigableContents fake_card_contents_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchResultAnswerCardViewTest);
 };
 
 TEST_F(SearchResultAnswerCardViewTest, Basic) {
   EXPECT_EQ(kDisplayScore, GetContainerScore());
-
   EXPECT_EQ(1, GetResultCountFromView());
-
-  // Result view should be added to the hierarchy.
-  EXPECT_EQ(search_card_view(), result_view()->parent()->parent()->parent());
   ASSERT_TRUE(search_card_view()->visible());
-
   EXPECT_EQ(1, GetYSize());
 }
 
@@ -149,7 +142,6 @@
 TEST_F(SearchResultAnswerCardViewTest, DeleteResult) {
   DeleteResult();
   EXPECT_EQ(0UL, GetResults()->item_count());
-  EXPECT_EQ(nullptr, result_view()->parent());
   EXPECT_EQ(0, GetYSize());
   ASSERT_FALSE(search_card_view()->visible());
   EXPECT_EQ(0, GetContainerScore());
diff --git a/ash/app_list/views/search_result_base_view.cc b/ash/app_list/views/search_result_base_view.cc
index 9a0d059..d9686f3 100644
--- a/ash/app_list/views/search_result_base_view.cc
+++ b/ash/app_list/views/search_result_base_view.cc
@@ -10,6 +10,13 @@
 
 SearchResultBaseView::~SearchResultBaseView() = default;
 
+bool SearchResultBaseView::SkipDefaultKeyEventProcessing(
+    const ui::KeyEvent& event) {
+  // Ensure accelerators take priority in the app list. This ensures, e.g., that
+  // Ctrl+Space will switch input methods rather than activate the button.
+  return false;
+}
+
 void SearchResultBaseView::SetBackgroundHighlighted(bool enabled) {
   background_highlighted_ = enabled;
   SchedulePaint();
diff --git a/ash/app_list/views/search_result_base_view.h b/ash/app_list/views/search_result_base_view.h
index aabcb60..5c30e4c 100644
--- a/ash/app_list/views/search_result_base_view.h
+++ b/ash/app_list/views/search_result_base_view.h
@@ -22,6 +22,9 @@
 
   bool background_highlighted() const { return background_highlighted_; }
 
+  // views::Button:
+  bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override;
+
  protected:
   ~SearchResultBaseView() override;
 
diff --git a/ash/app_menu/notification_menu_controller_unittest.cc b/ash/app_menu/notification_menu_controller_unittest.cc
index 5c5c94b..a4fdfbc 100644
--- a/ash/app_menu/notification_menu_controller_unittest.cc
+++ b/ash/app_menu/notification_menu_controller_unittest.cc
@@ -20,7 +20,7 @@
 void BuildAndSendNotification(const std::string& app_id,
                               const std::string& notification_id) {
   const message_center::NotifierId notifier_id(
-      message_center::NotifierId::APPLICATION, app_id);
+      message_center::NotifierType::APPLICATION, app_id);
   std::unique_ptr<message_center::Notification> notification =
       std::make_unique<message_center::Notification>(
           message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
diff --git a/ash/app_menu/notification_menu_view_unittest.cc b/ash/app_menu/notification_menu_view_unittest.cc
index 390f294..00ce257 100644
--- a/ash/app_menu/notification_menu_view_unittest.cc
+++ b/ash/app_menu/notification_menu_view_unittest.cc
@@ -121,7 +121,7 @@
       const base::string16& title,
       const base::string16& message) {
     const message_center::NotifierId notifier_id(
-        message_center::NotifierId::APPLICATION, kTestAppId);
+        message_center::NotifierType::APPLICATION, kTestAppId);
     message_center::Notification notification(
         message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
         message, gfx::Image(), base::ASCIIToUTF16("www.test.org"), GURL(),
@@ -137,7 +137,7 @@
       const base::string16& title,
       const base::string16& message) {
     const message_center::NotifierId notifier_id(
-        message_center::NotifierId::APPLICATION, kTestAppId);
+        message_center::NotifierType::APPLICATION, kTestAppId);
     message_center::Notification notification(
         message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
         message, gfx::Image(), base::ASCIIToUTF16("www.test.org"), GURL(),
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 12a46f2..639b3d0 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -279,6 +279,9 @@
       <message name="IDS_ASH_STATUS_TRAY_QUIET_MODE_TOOLTIP" desc="The tooltip text for the status area icon to tell do-not-disturb mode is currently on.">
         Do Not Disturb is on
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_INDICATOR_IME_TOOLTIP" desc="The tooltip text for the status area icon to tell the type of keyboard or input method engine.">
+        Using <ph name="IME_NAME">$1<ex>US keyboard</ex></ph>
+      </message>
       <message name="IDS_ASH_STATUS_TRAY_NOTIFICATIONS_COUNT_TOOLTIP" desc="The tooltip text for a status area icon to describe number of notifications. [ICU Syntax]">
         {NUM_NOTIFICATIONS, plural,
          =1 {1 notification}
@@ -787,6 +790,9 @@
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_DISCONNECTED_TOOLTIP" desc="The tooltip text used when network is not connected.">
         Disconnected
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED_A11Y" desc="The message used by accessibility for telling that currently the device is not connected to a network.">
+        Not connected to netowrk
+      </message>
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING_TOOLTIP" desc="The tooltip text used when network is connecting.">
         Connecting to <ph name="NETWORK_NAME">$1<ex>public wifi</ex></ph>
       </message>
@@ -1277,25 +1283,25 @@
         High contrast
       </message>
       <message name="IDS_ASH_HIGH_CONTRAST_BODY" desc="The text for the high contrast confirmation dialog.">
-        You pressed the shortcut for high contrast. Do you want to turn it on?
+        You pressed the keyboard shortcut for high contrast. Do you want to turn it on?
       </message>
       <message name="IDS_ASH_DOCKED_MAGNIFIER_TITLE" desc="Dialog title when docked magnifier is enabled.">
         Docked magnifier
       </message>
       <message name="IDS_ASH_DOCKED_MAGNIFIER_BODY" desc="The text for the docked magnifier dialog.">
-       You pressed the shortcut for the docked magnifier. Do you want to turn it on?
+        You pressed the keyboard shortcut for the docked magnifier. Do you want to turn it on?
       </message>
       <message name="IDS_ASH_SCREEN_MAGNIFIER_TITLE" desc="Dialog title when screen magnifier is enabled.">
         Full-screen magnifier
       </message>
       <message name="IDS_ASH_SCREEN_MAGNIFIER_BODY" desc="The text for the screen magnifier dialog.">
-       You pressed the shortcut for the full-screen magnifier. Do you want to turn it on?
+        You pressed the keyboard shortcut for the full-screen magnifier. Do you want to turn it on?
       </message>
       <message name="IDS_ASH_ROTATE_SCREEN_TITLE" desc="Dialog title for when the screen has been rotated.">
         Rotate Screen
       </message>
       <message name="IDS_ASH_ROTATE_SCREEN_BODY" desc="The text for the screen rotation dialog.">
-        You pressed the shortcut for screen rotation. Do you want to rotate the screen?
+        You pressed the keyboard shortcut for screen rotation. Do you want to rotate the screen?
       </message>
       <message name="IDS_ASH_CONTINUE_BUTTON" desc="The text for continue button on accessibility confirmation dialogs.">
         Continue
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED_A11Y.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED_A11Y.png.sha1
new file mode 100644
index 0000000..3e722b0
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED_A11Y.png.sha1
@@ -0,0 +1 @@
+4ec02c891501aa2b8bb43175f33c13e7846078dd
\ No newline at end of file
diff --git a/ash/assistant/assistant_cache_controller.cc b/ash/assistant/assistant_cache_controller.cc
index fdaacba..03f2beb 100644
--- a/ash/assistant/assistant_cache_controller.cc
+++ b/ash/assistant/assistant_cache_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/assistant/assistant_cache_controller.h"
 
+#include <utility>
 #include <vector>
 
 #include "ash/assistant/assistant_controller.h"
@@ -116,7 +117,8 @@
   if (!base::FeatureList::IsEnabled(kConversationStartersFeature))
     return;
 
-  using namespace chromeos::assistant::mojom;
+  using chromeos::assistant::mojom::AssistantSuggestion;
+  using chromeos::assistant::mojom::AssistantSuggestionPtr;
 
   std::vector<AssistantSuggestionPtr> conversation_starters;
 
@@ -134,7 +136,8 @@
 
   // If enabled, always show the "What's on my screen?" conversation starter.
   if (kWhatsOnMyScreenChipEnabled.Get() &&
-      Shell::Get()->voice_interaction_controller()->context_enabled()) {
+      Shell::Get()->voice_interaction_controller()->context_enabled().value_or(
+          false)) {
     AddConversationStarter(IDS_ASH_ASSISTANT_CHIP_WHATS_ON_MY_SCREEN,
                            assistant::util::CreateWhatsOnMyScreenDeepLink());
   }
diff --git a/ash/assistant/assistant_interaction_controller.cc b/ash/assistant/assistant_interaction_controller.cc
index c82f1c7..96f6c24 100644
--- a/ash/assistant/assistant_interaction_controller.cc
+++ b/ash/assistant/assistant_interaction_controller.cc
@@ -95,6 +95,9 @@
   using assistant::util::DeepLinkType;
 
   if (type == DeepLinkType::kWhatsOnMyScreen) {
+    // Explicitly call ShowUi() to set the correct Assistant entry point.
+    // ShowUi() will no-op if UI is already shown.
+    assistant_controller_->ui_controller()->ShowUi(AssistantSource::kDeepLink);
     StartScreenContextInteraction();
     return;
   }
@@ -116,6 +119,7 @@
     return;
   }
 
+  assistant_controller_->ui_controller()->ShowUi(AssistantSource::kDeepLink);
   StartTextInteraction(query.value());
 }
 
diff --git a/ash/assistant/assistant_notification_controller.cc b/ash/assistant/assistant_notification_controller.cc
index 0f3c727..e96e8dba 100644
--- a/ash/assistant/assistant_notification_controller.cc
+++ b/ash/assistant/assistant_notification_controller.cc
@@ -7,6 +7,7 @@
 #include "ash/assistant/assistant_controller.h"
 #include "ash/assistant/util/deep_link_util.h"
 #include "ash/new_window_controller.h"
+#include "ash/public/cpp/notification_utils.h"
 #include "ash/public/cpp/vector_icons/vector_icons.h"
 #include "ash/public/interfaces/voice_interaction_controller.mojom.h"
 #include "ash/shell.h"
@@ -98,7 +99,7 @@
 
 message_center::NotifierId GetNotifierId() {
   return message_center::NotifierId(
-      message_center::NotifierId::SYSTEM_COMPONENT, kNotifierAssistant);
+      message_center::NotifierType::SYSTEM_COMPONENT, kNotifierAssistant);
 }
 
 }  // namespace
@@ -157,7 +158,7 @@
   }
 
   std::unique_ptr<message_center::Notification> system_notification =
-      message_center::Notification::CreateSystemNotification(
+      ash::CreateSystemNotification(
           message_center::NOTIFICATION_TYPE_SIMPLE,
           GetNotificationId(notification->grouping_key), title, message,
           display_source, GURL(), notifier_id_, data,
diff --git a/ash/assistant/assistant_ui_controller.cc b/ash/assistant/assistant_ui_controller.cc
index 5fb6f26..6c4e043 100644
--- a/ash/assistant/assistant_ui_controller.cc
+++ b/ash/assistant/assistant_ui_controller.cc
@@ -10,6 +10,7 @@
 #include "ash/assistant/ui/assistant_container_view.h"
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/util/deep_link_util.h"
+#include "ash/assistant/util/histogram_util.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/toast/toast_data.h"
@@ -279,8 +280,12 @@
 }
 
 void AssistantUiController::ShowUi(AssistantSource source) {
-  if (!Shell::Get()->voice_interaction_controller()->settings_enabled())
+  if (!Shell::Get()
+           ->voice_interaction_controller()
+           ->settings_enabled()
+           .value_or(false)) {
     return;
+  }
 
   // TODO(dmblack): Show a more helpful message to the user.
   if (Shell::Get()->voice_interaction_controller()->voice_interaction_state() ==
@@ -300,6 +305,8 @@
     return;
   }
 
+  assistant::util::RecordAssistantEntryPoint(source);
+
   if (!container_view_)
     CreateContainerView();
 
@@ -311,7 +318,7 @@
 }
 
 void AssistantUiController::HideUi(AssistantSource source) {
-  if (model_.visibility() == AssistantVisibility::kHidden)
+  if (model_.visibility() != AssistantVisibility::kVisible)
     return;
 
   if (container_view_)
diff --git a/ash/assistant/ui/main_stage/assistant_footer_view.cc b/ash/assistant/ui/main_stage/assistant_footer_view.cc
index 4ac1ca0..8c198c0 100644
--- a/ash/assistant/ui/main_stage/assistant_footer_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_footer_view.cc
@@ -76,7 +76,8 @@
 
   // Initial view state is based on user consent state.
   const bool setup_completed =
-      Shell::Get()->voice_interaction_controller()->setup_completed();
+      Shell::Get()->voice_interaction_controller()->setup_completed().value_or(
+          false);
 
   // Suggestion container.
   suggestion_container_ = new SuggestionContainerView(assistant_controller_);
@@ -155,7 +156,8 @@
 bool AssistantFooterView::OnAnimationEnded(
     const ui::CallbackLayerAnimationObserver& observer) {
   const bool setup_completed =
-      Shell::Get()->voice_interaction_controller()->setup_completed();
+      Shell::Get()->voice_interaction_controller()->setup_completed().value_or(
+          false);
 
   // Only the view relevant to our consent state should process events.
   suggestion_container_->set_can_process_events_within_subtree(setup_completed);
diff --git a/ash/assistant/util/histogram_util.cc b/ash/assistant/util/histogram_util.cc
index 6830c48..1633d0b 100644
--- a/ash/assistant/util/histogram_util.cc
+++ b/ash/assistant/util/histogram_util.cc
@@ -15,6 +15,10 @@
   UMA_HISTOGRAM_ENUMERATION("Assistant.QueryCountPerEntryPoint", entry_point);
 }
 
+void RecordAssistantEntryPoint(AssistantSource entry_point) {
+  UMA_HISTOGRAM_ENUMERATION("Assistant.EntryPoint", entry_point);
+}
+
 }  // namespace util
 }  // namespace assistant
 }  // namespace ash
diff --git a/ash/assistant/util/histogram_util.h b/ash/assistant/util/histogram_util.h
index 8381284..4a46814e 100644
--- a/ash/assistant/util/histogram_util.h
+++ b/ash/assistant/util/histogram_util.h
@@ -15,6 +15,9 @@
 // Increment number of queries fired for each entry point.
 void IncrementAssistantQueryCountForEntryPoint(AssistantSource entry_point);
 
+// Record the entry point where Assistant UI becomes visible.
+void RecordAssistantEntryPoint(AssistantSource entry_point);
+
 }  // namespace util
 }  // namespace assistant
 }  // namespace ash
diff --git a/ash/components/fast_ink/fast_ink_view.cc b/ash/components/fast_ink/fast_ink_view.cc
index 085756a..37e41f7 100644
--- a/ash/components/fast_ink/fast_ink_view.cc
+++ b/ash/components/fast_ink/fast_ink_view.cc
@@ -159,7 +159,8 @@
                  gfx::Rect(holder->last_frame_size_in_pixels_),
                  gfx::Transform());
     frame.render_pass_list.push_back(std::move(pass));
-    holder->frame_sink_->SubmitCompositorFrame(std::move(frame));
+    holder->frame_sink_->SubmitCompositorFrame(std::move(frame),
+                                               /*show_hit_test_borders=*/false);
 
     // Delete sink holder immediately if not waiting for exported resources to
     // be reclaimed.
@@ -188,7 +189,8 @@
     exported_resources_[resource_id] = std::move(resource);
     last_frame_size_in_pixels_ = frame.size_in_pixels();
     last_frame_device_scale_factor_ = frame.metadata.device_scale_factor;
-    frame_sink_->SubmitCompositorFrame(std::move(frame));
+    frame_sink_->SubmitCompositorFrame(std::move(frame),
+                                       /*show_hit_test_borders=*/false);
   }
 
   void DamageExportedResources() {
@@ -232,6 +234,7 @@
     if (root_window_)
       ScheduleDelete();
   }
+  void DidNotNeedBeginFrame() override {}
   void OnDraw(const gfx::Transform& transform,
               const gfx::Rect& viewport,
               bool resourceless_software_draw,
diff --git a/ash/components/strings/ash_components_strings_am.xtb b/ash/components/strings/ash_components_strings_am.xtb
index 8e6133b8..12f4de3 100644
--- a/ash/components/strings/ash_components_strings_am.xtb
+++ b/ash/components/strings/ash_components_strings_am.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">አሁን ያለውን ገጽዎን ያትሙ</translation>
 <translation id="1383876407941801731">ፍለጋ </translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> ወይም <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">ወደ የመስመር መጨረሻ ይሂዱ</translation>
 <translation id="1510238584712386396">ማስጀመሪያ</translation>
 <translation id="152892567002884378">ድምጽ ጨምር</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />፣ ከዚያ <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">ይዘትን ከቅንጥብ ሰሌዳው ይለጥፉ</translation>
 <translation id="9052808072970550123">ወደ ቀጣዩ ተጠቃሚ ቀይር</translation>
 <translation id="906458777597946297">መስኮቱን ያስፉት</translation>
+<translation id="9091855755813503076">ወደ የመስመር መጀመሪያ ይሂዱ</translation>
 <translation id="9106898733795143799">ገጽ እና ድር አሳሽ</translation>
 <translation id="9162942292291287644">ለ<ph name="QUERY" /> ምንም የፍለጋ ውጤቶች የሉም</translation>
 <translation id="9179672198516322668">ታዋቂ አቋራጮች</translation>
diff --git a/ash/components/strings/ash_components_strings_ar.xtb b/ash/components/strings/ash_components_strings_ar.xtb
index 8e13edc..0af844a 100644
--- a/ash/components/strings/ash_components_strings_ar.xtb
+++ b/ash/components/strings/ash_components_strings_ar.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">طباعة الصفحة الحالية</translation>
 <translation id="1383876407941801731">البحث</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> أو <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">الانتقال إلى نهاية السطر</translation>
 <translation id="1510238584712386396">المشغّل</translation>
 <translation id="152892567002884378">رفع مستوى الصوت</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />، ثم <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">لصق المحتوى من الحافظة</translation>
 <translation id="9052808072970550123">التبديل إلى المستخدم التالي</translation>
 <translation id="906458777597946297">تكبير النافذة</translation>
+<translation id="9091855755813503076">الانتقال إلى بداية السطر</translation>
 <translation id="9106898733795143799">الصفحة ومتصفّح الويب</translation>
 <translation id="9162942292291287644">لم يتم العثور على أي نتائج بحث <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">الاختصارات الشائعة</translation>
diff --git a/ash/components/strings/ash_components_strings_bg.xtb b/ash/components/strings/ash_components_strings_bg.xtb
index e8916f0..8d678e0 100644
--- a/ash/components/strings/ash_components_strings_bg.xtb
+++ b/ash/components/strings/ash_components_strings_bg.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Отпечатване на текущата страница</translation>
 <translation id="1383876407941801731">Търсене</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> или <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Преминаване в края на реда</translation>
 <translation id="1510238584712386396">Стартов панел</translation>
 <translation id="152892567002884378">Увеличаване на силата на звука</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> и след това <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Поставяне на съдържанието от буферната памет</translation>
 <translation id="9052808072970550123">Превключване към следващия потребител</translation>
 <translation id="906458777597946297">Увеличаване на прозореца</translation>
+<translation id="9091855755813503076">Преминаване в началото на реда</translation>
 <translation id="9106898733795143799">Страница и уеб браузър</translation>
 <translation id="9162942292291287644">Няма резултати от търсенето на „<ph name="QUERY" />“</translation>
 <translation id="9179672198516322668">Популярни комбинации</translation>
diff --git a/ash/components/strings/ash_components_strings_bn.xtb b/ash/components/strings/ash_components_strings_bn.xtb
index d0fa6e2..7f58eac 100644
--- a/ash/components/strings/ash_components_strings_bn.xtb
+++ b/ash/components/strings/ash_components_strings_bn.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">আপনার বর্তমান পৃষ্ঠাটি প্রিন্ট করুন</translation>
 <translation id="1383876407941801731">সার্চ করুন</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> অথবা <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">লাইনের শেষে যান</translation>
 <translation id="1510238584712386396">লঞ্চার</translation>
 <translation id="152892567002884378">ভলিউম বাড়ান</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, তারপর <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">ক্লিপবোর্ড থেকে কন্টেন্ট পেস্ট করুন</translation>
 <translation id="9052808072970550123">পরের ব্যবহারকারী বেছে নিন</translation>
 <translation id="906458777597946297">উইন্ডো বৃহদায়ন করুন</translation>
+<translation id="9091855755813503076">লাইনের শুরুতে যান</translation>
 <translation id="9106898733795143799">পৃষ্ঠা এবং ওয়েব ব্রাউজার</translation>
 <translation id="9162942292291287644"><ph name="QUERY" /> এর কোনও ফলাফল পাওয়া যায়নি</translation>
 <translation id="9179672198516322668">জনপ্রিয় শর্টকাট</translation>
diff --git a/ash/components/strings/ash_components_strings_ca.xtb b/ash/components/strings/ash_components_strings_ca.xtb
index b4c6489..6112c6f 100644
--- a/ash/components/strings/ash_components_strings_ca.xtb
+++ b/ash/components/strings/ash_components_strings_ca.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Imprimeix la pàgina actual</translation>
 <translation id="1383876407941801731">Cerca</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> o <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Ves al final de la línia</translation>
 <translation id="1510238584712386396">Menú d'aplicacions</translation>
 <translation id="152892567002884378">Apuja el volum</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> i després <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Enganxa el contingut del porta-retalls</translation>
 <translation id="9052808072970550123">Canvia a l'usuari següent</translation>
 <translation id="906458777597946297">Maximitza la finestra</translation>
+<translation id="9091855755813503076">Ves al principi de la línia</translation>
 <translation id="9106898733795143799">Pàgina i navegador web</translation>
 <translation id="9162942292291287644">No hi ha resultats de cerca per a <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Dreceres populars</translation>
diff --git a/ash/components/strings/ash_components_strings_cs.xtb b/ash/components/strings/ash_components_strings_cs.xtb
index 8d8ab0d..76b0a2c 100644
--- a/ash/components/strings/ash_components_strings_cs.xtb
+++ b/ash/components/strings/ash_components_strings_cs.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Vytisknout aktuální stránku</translation>
 <translation id="1383876407941801731">Vyhledávání</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> nebo <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Přejít na konec řádku</translation>
 <translation id="1510238584712386396">Spouštěč</translation>
 <translation id="152892567002884378">Zvýšit hlasitost</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> a poté <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Vložit obsah ze schránky</translation>
 <translation id="9052808072970550123">Přepnout na dalšího uživatele</translation>
 <translation id="906458777597946297">Maximalizovat okno</translation>
+<translation id="9091855755813503076">Přejít na začátek řádku</translation>
 <translation id="9106898733795143799">Stránka a webový prohlížeč</translation>
 <translation id="9162942292291287644">Žádné výsledky vyhledávání na téma <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Oblíbené klávesové zkratky</translation>
diff --git a/ash/components/strings/ash_components_strings_da.xtb b/ash/components/strings/ash_components_strings_da.xtb
index d9988e4..48a6c32 100644
--- a/ash/components/strings/ash_components_strings_da.xtb
+++ b/ash/components/strings/ash_components_strings_da.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Udskriv den aktuelle side</translation>
 <translation id="1383876407941801731">Søg</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> eller <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Gå til slutningen af linjen</translation>
 <translation id="1510238584712386396">Appliste</translation>
 <translation id="152892567002884378">Lydstyrke op</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> og derefter <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Indsæt indholdet fra udklipsholderen</translation>
 <translation id="9052808072970550123">Skift til næste bruger</translation>
 <translation id="906458777597946297">Maksimér vinduet</translation>
+<translation id="9091855755813503076">Gå til begyndelsen af linjen</translation>
 <translation id="9106898733795143799">Side- og webbrowser</translation>
 <translation id="9162942292291287644">Der er ingen søgeresultater for <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Populære genveje</translation>
diff --git a/ash/components/strings/ash_components_strings_de.xtb b/ash/components/strings/ash_components_strings_de.xtb
index afeaebd..7ceba8c 100644
--- a/ash/components/strings/ash_components_strings_de.xtb
+++ b/ash/components/strings/ash_components_strings_de.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Aktuelle Seite drucken</translation>
 <translation id="1383876407941801731">Suchen</translation>
 <translation id="1454364489140280055">"<ph name="CTRL" />" <ph name="SEPARATOR1" /> "<ph name="SHIFT1" />" <ph name="SEPARATOR2" /> "<ph name="G" />" oder "<ph name="SHIFT2" />" <ph name="SEPARATOR3" /> "<ph name="ENTER" />"</translation>
+<translation id="1477442857810932985">Zum Zeilenende springen</translation>
 <translation id="1510238584712386396">Übersicht</translation>
 <translation id="152892567002884378">Lauter</translation>
 <translation id="1560480564179555003">"<ph name="SHIFT" />" <ph name="SEPARATOR1" /> "<ph name="ALT" />" <ph name="SEPARATOR2" /> "<ph name="L" />", dann "<ph name="ESC" />"</translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Inhalt aus der Zwischenablage einfügen</translation>
 <translation id="9052808072970550123">Zum nächsten Nutzer wechseln</translation>
 <translation id="906458777597946297">Fenster maximieren</translation>
+<translation id="9091855755813503076">Zum Zeilenanfang springen</translation>
 <translation id="9106898733795143799">Seite &amp; Webbrowser</translation>
 <translation id="9162942292291287644">Kein Suchergebnis für <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Häufig verwendete Tastenkombinationen</translation>
diff --git a/ash/components/strings/ash_components_strings_el.xtb b/ash/components/strings/ash_components_strings_el.xtb
index e2d2425..72cea37 100644
--- a/ash/components/strings/ash_components_strings_el.xtb
+++ b/ash/components/strings/ash_components_strings_el.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Εκτύπωση της τρέχουσας σελίδας</translation>
 <translation id="1383876407941801731">Αναζήτηση</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> ή <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Μετάβαση στο τέλος της γραμμής</translation>
 <translation id="1510238584712386396">Λειτουργία εκκίνησης</translation>
 <translation id="152892567002884378">Αύξηση έντασης ήχου</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> και έπειτα <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Επικόλληση περιεχομένου από το πρόχειρο</translation>
 <translation id="9052808072970550123">Εναλλαγή στον επόμενο χρήστη</translation>
 <translation id="906458777597946297">Μεγιστοποίηση παραθύρου</translation>
+<translation id="9091855755813503076">Μετάβαση στην αρχή της γραμμής</translation>
 <translation id="9106898733795143799">Πρόγραμμα περιήγησης στον ιστό και σε σελίδες</translation>
 <translation id="9162942292291287644">Κανένα αποτέλεσμα αναζήτησης για <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Δημοφιλείς συντομεύσεις</translation>
diff --git a/ash/components/strings/ash_components_strings_en-GB.xtb b/ash/components/strings/ash_components_strings_en-GB.xtb
index b70c1e7..76df160a 100644
--- a/ash/components/strings/ash_components_strings_en-GB.xtb
+++ b/ash/components/strings/ash_components_strings_en-GB.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Print your current page</translation>
 <translation id="1383876407941801731">Search</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> or <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Go to end of line</translation>
 <translation id="1510238584712386396">Launcher</translation>
 <translation id="152892567002884378">Volume up</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, then <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Paste content from the clipboard</translation>
 <translation id="9052808072970550123">Switch to the next user</translation>
 <translation id="906458777597946297">Maximise window</translation>
+<translation id="9091855755813503076">Go to beginning of line</translation>
 <translation id="9106898733795143799">Page &amp; Web Browser</translation>
 <translation id="9162942292291287644">No search result for <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Popular Shortcuts</translation>
diff --git a/ash/components/strings/ash_components_strings_es-419.xtb b/ash/components/strings/ash_components_strings_es-419.xtb
index 1a41609..c946541 100644
--- a/ash/components/strings/ash_components_strings_es-419.xtb
+++ b/ash/components/strings/ash_components_strings_es-419.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Imprimir la página actual</translation>
 <translation id="1383876407941801731">Buscar</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> o <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Ir al final de la línea</translation>
 <translation id="1510238584712386396">Selector</translation>
 <translation id="152892567002884378">Subir el volumen</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, luego <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Pegar el contenido del portapapeles</translation>
 <translation id="9052808072970550123">Cambiar al usuario siguiente</translation>
 <translation id="906458777597946297">Maximizar ventana</translation>
+<translation id="9091855755813503076">Ir al comienzo de la línea</translation>
 <translation id="9106898733795143799">Página y navegador web</translation>
 <translation id="9162942292291287644">No se encontraron resultados de búsqueda para <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Combinaciones de teclas populares</translation>
diff --git a/ash/components/strings/ash_components_strings_es.xtb b/ash/components/strings/ash_components_strings_es.xtb
index 086ca29..60fea88 100644
--- a/ash/components/strings/ash_components_strings_es.xtb
+++ b/ash/components/strings/ash_components_strings_es.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Imprimir la página actual</translation>
 <translation id="1383876407941801731">Buscar</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> o <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Ir al final de la línea</translation>
 <translation id="1510238584712386396">Menú de aplicaciones</translation>
 <translation id="152892567002884378">Subir el volumen</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> y <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Pegar el contenido del portapapeles</translation>
 <translation id="9052808072970550123">Cambiar al usuario siguiente</translation>
 <translation id="906458777597946297">Maximizar ventana</translation>
+<translation id="9091855755813503076">Ir al principio de la línea</translation>
 <translation id="9106898733795143799">Página y navegador web</translation>
 <translation id="9162942292291287644">No se ha encontrado ningún resultado de búsqueda de <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Combinaciones de teclas populares</translation>
diff --git a/ash/components/strings/ash_components_strings_et.xtb b/ash/components/strings/ash_components_strings_et.xtb
index 8028b4d..40065c5d 100644
--- a/ash/components/strings/ash_components_strings_et.xtb
+++ b/ash/components/strings/ash_components_strings_et.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Aktiivse lehe printimine</translation>
 <translation id="1383876407941801731">Otsi</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /> <ph name="SEPARATOR1" /> <ph name="SHIFT1" /> <ph name="SEPARATOR2" /> <ph name="G" /> või <ph name="SHIFT2" /> <ph name="SEPARATOR3" /> <ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Mine rea lõppu</translation>
 <translation id="1510238584712386396">Käivitaja</translation>
 <translation id="152892567002884378">Helitugevuse suurendamine</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /> <ph name="SEPARATOR1" /> <ph name="ALT" /> <ph name="SEPARATOR2" /> <ph name="L" />, seejärel <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Lõikelaua sisu kleepimine</translation>
 <translation id="9052808072970550123">Järgmisele kasutajale vahetamine</translation>
 <translation id="906458777597946297">Maksimeeri akent</translation>
+<translation id="9091855755813503076">Mine rea algusesse</translation>
 <translation id="9106898733795143799">Leht ja veebibrauser</translation>
 <translation id="9162942292291287644">Päringule <ph name="QUERY" /> ei leitud otsingutulemusi</translation>
 <translation id="9179672198516322668">Populaarsed otseteed</translation>
diff --git a/ash/components/strings/ash_components_strings_fa.xtb b/ash/components/strings/ash_components_strings_fa.xtb
index 592376c4..0508ae8f 100644
--- a/ash/components/strings/ash_components_strings_fa.xtb
+++ b/ash/components/strings/ash_components_strings_fa.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">چاپ صفحه کنونی</translation>
 <translation id="1383876407941801731">جستجو</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> یا <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">رفتن به انتهای خط</translation>
 <translation id="1510238584712386396">راه‌انداز</translation>
 <translation id="152892567002884378">افزایش صدا</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> و سپس <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">جای‌گذاری محتوا از کلیپ‌بورد</translation>
 <translation id="9052808072970550123">جابه‌جا شدن به کاربر بعدی</translation>
 <translation id="906458777597946297">بازکردن پنجره در حداکثر اندازه</translation>
+<translation id="9091855755813503076">رفتن به ابتدای خط</translation>
 <translation id="9106898733795143799">صفحه و مرورگر وب</translation>
 <translation id="9162942292291287644">هیچ نتیجه جستجویی برای <ph name="QUERY" /> وجود ندارد</translation>
 <translation id="9179672198516322668">میان‌برهای پرطرفدار</translation>
diff --git a/ash/components/strings/ash_components_strings_fi.xtb b/ash/components/strings/ash_components_strings_fi.xtb
index 8e1ba70..c0045b9 100644
--- a/ash/components/strings/ash_components_strings_fi.xtb
+++ b/ash/components/strings/ash_components_strings_fi.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Tulosta nykyinen sivu</translation>
 <translation id="1383876407941801731">Haku</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> tai <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Siirry rivin loppuun</translation>
 <translation id="1510238584712386396">Käynnistysohjelma</translation>
 <translation id="152892567002884378">Lisää äänenvoimakkuutta</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, sitten <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Liitä leikepöydän sisältö</translation>
 <translation id="9052808072970550123">Vaihda seuraavaan käyttäjään</translation>
 <translation id="906458777597946297">Suurenna ikkuna</translation>
+<translation id="9091855755813503076">Siirry rivin alkuun</translation>
 <translation id="9106898733795143799">Sivu ja verkkoselain</translation>
 <translation id="9162942292291287644">Ei hakutuloksia kyselylle <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Suositut pikanäppäimet</translation>
diff --git a/ash/components/strings/ash_components_strings_fil.xtb b/ash/components/strings/ash_components_strings_fil.xtb
index 868eb71..6a2149b 100644
--- a/ash/components/strings/ash_components_strings_fil.xtb
+++ b/ash/components/strings/ash_components_strings_fil.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">I-print ang iyong kasalukuyang page</translation>
 <translation id="1383876407941801731">Hanapin</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> o <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Pumunta sa dulo ng linya</translation>
 <translation id="1510238584712386396">Launcher</translation>
 <translation id="152892567002884378">Lakasan ang volume</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, pagkatapos ay <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">I-paste ang content mula sa clipboard</translation>
 <translation id="9052808072970550123">Lumipat sa susunod na user</translation>
 <translation id="906458777597946297">I-maximize ang window</translation>
+<translation id="9091855755813503076">Pumunta sa simula ng linya</translation>
 <translation id="9106898733795143799">Page at Web Browser</translation>
 <translation id="9162942292291287644">Walang resulta ng paghahanap para sa <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Mga Sikat na Shortcut</translation>
diff --git a/ash/components/strings/ash_components_strings_fr.xtb b/ash/components/strings/ash_components_strings_fr.xtb
index 41afe40..840c83a 100644
--- a/ash/components/strings/ash_components_strings_fr.xtb
+++ b/ash/components/strings/ash_components_strings_fr.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Imprimer la page active</translation>
 <translation id="1383876407941801731">Rechercher</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> ou <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Accéder à la fin de la ligne</translation>
 <translation id="1510238584712386396">Lanceur d'applications</translation>
 <translation id="152892567002884378">Augmenter le volume</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, puis <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Coller le contenu du Presse-papiers</translation>
 <translation id="9052808072970550123">Passer à l'utilisateur suivant</translation>
 <translation id="906458777597946297">Agrandir la fenêtre</translation>
+<translation id="9091855755813503076">Accéder au début de la ligne</translation>
 <translation id="9106898733795143799">Page et navigateur Web</translation>
 <translation id="9162942292291287644">Aucun résultat de recherche pour <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Raccourcis courants</translation>
diff --git a/ash/components/strings/ash_components_strings_gu.xtb b/ash/components/strings/ash_components_strings_gu.xtb
index a1396ea..8e3e3f9 100644
--- a/ash/components/strings/ash_components_strings_gu.xtb
+++ b/ash/components/strings/ash_components_strings_gu.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">તમારું વર્તમાન પેજ પ્રિન્ટ કરો</translation>
 <translation id="1383876407941801731">શોધો</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> અથવા <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">રેખાના અંત પર જાઓ</translation>
 <translation id="1510238584712386396">લૉન્ચર</translation>
 <translation id="152892567002884378">વૉલ્યૂમ વધારો</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, પછી <ph name="ESC" /></translation>
@@ -39,7 +40,7 @@
 <translation id="2454251766545114447">ડિસ્પ્લે ઝૂમ ઘટાડો</translation>
 <translation id="2478303094958140141">ChromeVox (બોલાયેલ પ્રતિસાદ) ચાલુ અથવા બંધ કરો</translation>
 <translation id="2515586267016047495">Alt</translation>
-<translation id="2530339807289914946">વેબપેજને નીચે સ્ક્રોલ કરો</translation>
+<translation id="2530339807289914946">વેબપેજમાં નીચે સ્ક્રોલ કરો</translation>
 <translation id="2574014812750545982">પેજ પર ઝૂમ લેવલ રીસેટ કરો</translation>
 <translation id="2596078834055697711">વિંડો સ્ક્રીનશૉટ લો</translation>
 <translation id="2685170433750953446"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, પછી <ph name="TAB" /> અથવા <ph name="RIGHT" /></translation>
@@ -95,7 +96,7 @@
 <translation id="4556221320735744018">કીબોર્ડ શૉર્ટકટ સહાયક જુઓ</translation>
 <translation id="4628718545549558538">સ્ટેટસ એરિયા ખોલો (જ્યાં તમારું એકાઉન્ટનું ફોટો દેખાય છે ત્યાં ક્લિક કરો)</translation>
 <translation id="4642092649622328492">આંશિક સ્ક્રીનશૉટ લો</translation>
-<translation id="4698850295812410683">સ્ટાઇલસના સાધનો બતાવો</translation>
+<translation id="4698850295812410683">સ્ટાઇલસનાં સાધનો બતાવો</translation>
 <translation id="4801989101741319327">આગલા શબ્દના અંતે જાઓ</translation>
 <translation id="4916163929714267752">લિંકને નવી વિંડોમાં ખોલો</translation>
 <translation id="5030659775136592441">બુકમાર્ક મેનેજર બતાવો</translation>
@@ -168,7 +169,7 @@
 <translation id="8026334261755873520">બ્રાઉઝિંગ ડેટા સાફ કરો</translation>
 <translation id="8130528849632411619">દસ્તાવેજની શરૂઆત પર જાઓ</translation>
 <translation id="8147954207400281792"><ph name="CTRL" /><ph name="SEPARATOR" /><ph name="K" /> અથવા <ph name="E" /></translation>
-<translation id="8232835244134740473">આની વચ્ચે ફોકસ સ્વિચ કરો: સ્ટેટસ એરિયા (જ્યાં તમારા એકાઉન્ટનું ફોટો દેખાય છે), લૉન્ચર, ઍડ્રેસ બાર, બુકમાર્ક બાર (જો દૃશ્યક્ષમ હોય, તો), ખુલ્લું છે તે વેબપેજ અને ડાઉનલોડ બાર (જો દૃશ્યક્ષમ હોય, તો).</translation>
+<translation id="8232835244134740473">આની વચ્ચે ફોકસ સ્વિચ કરો: સ્ટેટસ એરિયા (જ્યાં તમારા એકાઉન્ટનો ફોટો દેખાય છે), લૉન્ચર, ઍડ્રેસ બાર, બુકમાર્ક બાર (જો દેખાતી હોય, તો), ખુલ્લું છે તે વેબપેજ અને ડાઉનલોડ બાર (જો દેખાતી હોય, તો).</translation>
 <translation id="8234414138295101081">સ્ક્રીનને 90 ડિગ્રીએ ફેરવો</translation>
 <translation id="8264941229485248811">ડેવલપર સાધનો ઇન્સ્પેક્ટર બતાવો અથવા છુપાવો</translation>
 <translation id="836869401750819675">ડાઉનલોડ પેજ ખોલો</translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">ક્લિપબોર્ડ પરનું કન્ટેન્ટ પેસ્ટ કરો</translation>
 <translation id="9052808072970550123">આગલા વપરાશકર્તા પર સ્વિચ કરો</translation>
 <translation id="906458777597946297">વિંડો મોટી કરો</translation>
+<translation id="9091855755813503076">રેખાની શરૂઆત પર જાઓ</translation>
 <translation id="9106898733795143799">પેજ અને વેબ બ્રાઉઝર</translation>
 <translation id="9162942292291287644"><ph name="QUERY" /> માટે કોઈ શોધ પરિણામ નથી</translation>
 <translation id="9179672198516322668">લોકપ્રિય શૉર્ટકટ</translation>
diff --git a/ash/components/strings/ash_components_strings_hi.xtb b/ash/components/strings/ash_components_strings_hi.xtb
index e43fe30..43d4a6c 100644
--- a/ash/components/strings/ash_components_strings_hi.xtb
+++ b/ash/components/strings/ash_components_strings_hi.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">अपना अभी वाला पेज प्रिंट करें</translation>
 <translation id="1383876407941801731">खोज</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> या <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">लाइन के आखिर में जाएं</translation>
 <translation id="1510238584712386396">लॉन्चर</translation>
 <translation id="152892567002884378">वॉल्यूम बढ़ाएं</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, फिर <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">क्लिपबोर्ड से सामग्री चिपकाएं</translation>
 <translation id="9052808072970550123">अगले उपयोगकर्ता पर जाएं</translation>
 <translation id="906458777597946297">विंडो को बड़ा करें</translation>
+<translation id="9091855755813503076">लाइन के शुरू में जाएं</translation>
 <translation id="9106898733795143799">पेज और वेब ब्राउज़र</translation>
 <translation id="9162942292291287644"><ph name="QUERY" /> के लिए कोई सर्च नतीजा नहीं</translation>
 <translation id="9179672198516322668">लोकप्रिय शॉर्टकट</translation>
diff --git a/ash/components/strings/ash_components_strings_hr.xtb b/ash/components/strings/ash_components_strings_hr.xtb
index 3aa8533..ca219da3 100644
--- a/ash/components/strings/ash_components_strings_hr.xtb
+++ b/ash/components/strings/ash_components_strings_hr.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Ispis trenutačne stranice</translation>
 <translation id="1383876407941801731">Traži</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> ili <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Prelazak na kraj retka</translation>
 <translation id="1510238584712386396">Pokretač</translation>
 <translation id="152892567002884378">Pojačavanje glasnoće</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, a zatim <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Lijepljenje sadržaja iz međuspremnika</translation>
 <translation id="9052808072970550123">Prelazak na sljedećeg korisnika</translation>
 <translation id="906458777597946297">Maksimiziranje prozora</translation>
+<translation id="9091855755813503076">Prelazak na početak retka</translation>
 <translation id="9106898733795143799">Stranica i web-preglednik</translation>
 <translation id="9162942292291287644">Nema rezultata pretraživanja za upit <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Popularni prečaci</translation>
diff --git a/ash/components/strings/ash_components_strings_hu.xtb b/ash/components/strings/ash_components_strings_hu.xtb
index 3f9b5c6..a96e14e 100644
--- a/ash/components/strings/ash_components_strings_hu.xtb
+++ b/ash/components/strings/ash_components_strings_hu.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Az aktuális oldal nyomtatása</translation>
 <translation id="1383876407941801731">Keresés</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> vagy <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Ugrás a sor végére</translation>
 <translation id="1510238584712386396">Indító</translation>
 <translation id="152892567002884378">Hangerő növelése</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, majd <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Tartalom beillesztése a vágólapról</translation>
 <translation id="9052808072970550123">Váltás a következő felhasználóra</translation>
 <translation id="906458777597946297">Ablak teljes méretre állítása</translation>
+<translation id="9091855755813503076">Ugrás a sor elejére</translation>
 <translation id="9106898733795143799">Oldal és böngésző</translation>
 <translation id="9162942292291287644">Nincs keresési találat a következőre: <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Népszerű billentyűparancsok</translation>
diff --git a/ash/components/strings/ash_components_strings_id.xtb b/ash/components/strings/ash_components_strings_id.xtb
index cf0972b..ba08276 100644
--- a/ash/components/strings/ash_components_strings_id.xtb
+++ b/ash/components/strings/ash_components_strings_id.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Mencetak halaman aktif</translation>
 <translation id="1383876407941801731">Telusuri</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> atau <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Ke akhir baris</translation>
 <translation id="1510238584712386396">Peluncur</translation>
 <translation id="152892567002884378">Mengeraskan volume</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, lalu <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Menempelkan konten dari papan klip</translation>
 <translation id="9052808072970550123">Beralih ke pengguna berikutnya</translation>
 <translation id="906458777597946297">Memaksimalkan jendela</translation>
+<translation id="9091855755813503076">Ke awal baris</translation>
 <translation id="9106898733795143799">Halaman &amp; Browser Web</translation>
 <translation id="9162942292291287644">Tidak ditemukan hasil penelusuran untuk <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Pintasan Populer</translation>
diff --git a/ash/components/strings/ash_components_strings_it.xtb b/ash/components/strings/ash_components_strings_it.xtb
index 0b2e337..495d076 100644
--- a/ash/components/strings/ash_components_strings_it.xtb
+++ b/ash/components/strings/ash_components_strings_it.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Stampa la pagina corrente</translation>
 <translation id="1383876407941801731">Cerca</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> o <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Vai alla fine della riga</translation>
 <translation id="1510238584712386396">Avvio applicazioni</translation>
 <translation id="152892567002884378">Alza il volume</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, quindi <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Incolla i contenuti dagli appunti</translation>
 <translation id="9052808072970550123">Passa all'utente successivo</translation>
 <translation id="906458777597946297">Ingrandisci la finestra</translation>
+<translation id="9091855755813503076">Vai all'inizio della riga</translation>
 <translation id="9106898733795143799">Pagina e browser web</translation>
 <translation id="9162942292291287644">Nessun risultato di ricerca relativo a <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Scorciatoie comuni</translation>
diff --git a/ash/components/strings/ash_components_strings_iw.xtb b/ash/components/strings/ash_components_strings_iw.xtb
index 2aad8db..4ca07e4 100644
--- a/ash/components/strings/ash_components_strings_iw.xtb
+++ b/ash/components/strings/ash_components_strings_iw.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">הדפסת הדף הנוכחי</translation>
 <translation id="1383876407941801731">חפש</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> או <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">מעבר לסוף השורה</translation>
 <translation id="1510238584712386396">מפעיל</translation>
 <translation id="152892567002884378">הגברת עוצמת הקול</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> ואז <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">הדבקת התוכן מהלוח</translation>
 <translation id="9052808072970550123">מעבר למשתמש הבא</translation>
 <translation id="906458777597946297">הגדל את החלון</translation>
+<translation id="9091855755813503076">מעבר לתחילת השורה</translation>
 <translation id="9106898733795143799">דפים ודפדפן אינטרנט</translation>
 <translation id="9162942292291287644">אין תוצאות חיפוש לגבי <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">מקשי קיצור בשימוש נפוץ</translation>
diff --git a/ash/components/strings/ash_components_strings_ja.xtb b/ash/components/strings/ash_components_strings_ja.xtb
index 4b43726b..b13b50f 100644
--- a/ash/components/strings/ash_components_strings_ja.xtb
+++ b/ash/components/strings/ash_components_strings_ja.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">現在のページを印刷する</translation>
 <translation id="1383876407941801731">検索</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> キーまたは <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /> キーを押す</translation>
+<translation id="1477442857810932985">行の末尾に移動します</translation>
 <translation id="1510238584712386396">ランチャー</translation>
 <translation id="152892567002884378">音量を上げる</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> キーを押した状態で <ph name="ESC" /> キーを押す</translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">クリップボードの内容を貼り付けます</translation>
 <translation id="9052808072970550123">次のユーザーに切り替えます</translation>
 <translation id="906458777597946297">ウィンドウを最大化</translation>
+<translation id="9091855755813503076">行の先頭に移動します</translation>
 <translation id="9106898733795143799">ページとウェブブラウザ</translation>
 <translation id="9162942292291287644">「<ph name="QUERY" />」の検索結果はありません</translation>
 <translation id="9179672198516322668">定番のショートカット</translation>
diff --git a/ash/components/strings/ash_components_strings_kn.xtb b/ash/components/strings/ash_components_strings_kn.xtb
index a8ae4085..95fcd0e 100644
--- a/ash/components/strings/ash_components_strings_kn.xtb
+++ b/ash/components/strings/ash_components_strings_kn.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಪುಟವನ್ನು ಮುದ್ರಿಸಿ</translation>
 <translation id="1383876407941801731">ಹುಡುಕಾಟ</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> ಅಥವಾ <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">ಸಾಲಿನ ಅಂತ್ಯಕ್ಕೆ ಹೋಗಿ</translation>
 <translation id="1510238584712386396">ಲಾಂಚರ್</translation>
 <translation id="152892567002884378">ವಾಲ್ಯೂಮ್ ಹೆಚ್ಚು ಮಾಡಿ</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, ನಂತರ <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಿಂದ ವಿಷಯವನ್ನು ಅಂಟಿಸಿ</translation>
 <translation id="9052808072970550123">ಮುಂದಿನ ಬಳಕೆದಾರರಿಗೆ ಬದಲಿಸಿ</translation>
 <translation id="906458777597946297">ವಿಂಡೋ ಹಿರಿದಾಗಿಸಿ</translation>
+<translation id="9091855755813503076">ಸಾಲಿನ ಪ್ರಾರಂಭಕ್ಕೆ ಹೋಗಿ</translation>
 <translation id="9106898733795143799">ಪುಟ ಮತ್ತು ವೆಬ್ ಬ್ರೌಸರ್</translation>
 <translation id="9162942292291287644"><ph name="QUERY" /> ಗಾಗಿ ಯಾವುದೇ ಫಲಿತಾಂಶಗಳಿಲ್ಲ</translation>
 <translation id="9179672198516322668">ಜನಪ್ರಿಯ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು</translation>
diff --git a/ash/components/strings/ash_components_strings_ko.xtb b/ash/components/strings/ash_components_strings_ko.xtb
index 39210055..4a4d633 100644
--- a/ash/components/strings/ash_components_strings_ko.xtb
+++ b/ash/components/strings/ash_components_strings_ko.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">현재 페이지를 인쇄</translation>
 <translation id="1383876407941801731">검색</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> 또는 <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">행의 끝으로 이동</translation>
 <translation id="1510238584712386396">런처</translation>
 <translation id="152892567002884378">볼륨 크게</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />을 누르고 <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">클립보드에서 콘텐츠 붙여넣기</translation>
 <translation id="9052808072970550123">다음 사용자로 전환</translation>
 <translation id="906458777597946297">창 최대화</translation>
+<translation id="9091855755813503076">행의 처음으로 이동</translation>
 <translation id="9106898733795143799">페이지 및 웹브라우저</translation>
 <translation id="9162942292291287644"><ph name="QUERY" /> 검색결과 없음</translation>
 <translation id="9179672198516322668">자주 쓰는 단축키</translation>
diff --git a/ash/components/strings/ash_components_strings_lt.xtb b/ash/components/strings/ash_components_strings_lt.xtb
index 4ba1604..8475822 100644
--- a/ash/components/strings/ash_components_strings_lt.xtb
+++ b/ash/components/strings/ash_components_strings_lt.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Spausdinti dabartinį puslapį</translation>
 <translation id="1383876407941801731">Ieškoti</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> arba <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Eiti į eilutės pabaigą</translation>
 <translation id="1510238584712386396">Paleidimo priemonė</translation>
 <translation id="152892567002884378">Padidinti garsumą</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, tada <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Įklijuoti turinį iš iškarpinės</translation>
 <translation id="9052808072970550123">Perjungti į kitą naudotoją</translation>
 <translation id="906458777597946297">Padidinti langą</translation>
+<translation id="9091855755813503076">Eiti į eilutės pradžią</translation>
 <translation id="9106898733795143799">Puslapis ir žiniatinklio naršyklė</translation>
 <translation id="9162942292291287644">Nėra paieškos rezultatų pagal užklausą „<ph name="QUERY" />“</translation>
 <translation id="9179672198516322668">Populiarūs spartieji klavišai</translation>
diff --git a/ash/components/strings/ash_components_strings_lv.xtb b/ash/components/strings/ash_components_strings_lv.xtb
index f1cbba1f..86a4079 100644
--- a/ash/components/strings/ash_components_strings_lv.xtb
+++ b/ash/components/strings/ash_components_strings_lv.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Drukāt pašreizējo lapu</translation>
 <translation id="1383876407941801731">Meklēt</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> vai <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Pāriet uz rindas beigām</translation>
 <translation id="1510238584712386396">Lietojumprogrammu palaidējs</translation>
 <translation id="152892567002884378">Palielināt skaļumu</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, pēc tam <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Ielīmēt saturu no starpliktuves</translation>
 <translation id="9052808072970550123">Pārslēgt nākamo lietotāju</translation>
 <translation id="906458777597946297">Maksimizēt logu</translation>
+<translation id="9091855755813503076">Pāriet uz rindas sākumu</translation>
 <translation id="9106898733795143799">Lapa un tīmekļa pārlūks</translation>
 <translation id="9162942292291287644">Nav meklēšanas rezultātu vaicājumam “<ph name="QUERY" />”.</translation>
 <translation id="9179672198516322668">Populāri īsinājumtaustiņi</translation>
diff --git a/ash/components/strings/ash_components_strings_ml.xtb b/ash/components/strings/ash_components_strings_ml.xtb
index db98226..a5038f0 100644
--- a/ash/components/strings/ash_components_strings_ml.xtb
+++ b/ash/components/strings/ash_components_strings_ml.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">നിങ്ങളുടെ നിലവിലെ പേജ് പ്രിന്റ് ചെയ്യുക</translation>
 <translation id="1383876407941801731">തിരയൂ</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> അല്ലെങ്കിൽ <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">വരിയുടെ അവസാനത്തിലേക്ക് പോകുക</translation>
 <translation id="1510238584712386396">ലോഞ്ചർ</translation>
 <translation id="152892567002884378">ശബ്ദം കൂട്ടുക</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, തുടർന്ന് <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">ക്ലിപ്‌ബോർഡിൽ നിന്നുള്ള ഉള്ളടക്കം ഒട്ടിക്കുക</translation>
 <translation id="9052808072970550123">അടുത്ത ഉപയോക്താവിലേക്ക് മാറുക</translation>
 <translation id="906458777597946297">വിൻഡോ വലുതാക്കുക</translation>
+<translation id="9091855755813503076">വരിയുടെ തുടക്കത്തിലേക്ക് പോകുക</translation>
 <translation id="9106898733795143799">പേജും വെബ് ബ്രൗസറും</translation>
 <translation id="9162942292291287644"><ph name="QUERY" /> എന്നതിനായി തിരയൽ ഫലമൊന്നുമില്ല</translation>
 <translation id="9179672198516322668">ജനപ്രിയ കുറുക്കുവഴികൾ</translation>
diff --git a/ash/components/strings/ash_components_strings_mr.xtb b/ash/components/strings/ash_components_strings_mr.xtb
index d26b34c..91499f64 100644
--- a/ash/components/strings/ash_components_strings_mr.xtb
+++ b/ash/components/strings/ash_components_strings_mr.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">तुमचे हे पेज प्रिंट करा</translation>
 <translation id="1383876407941801731">शोधा</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> किंवा <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">ओळीच्या शेवटी जा</translation>
 <translation id="1510238584712386396">लाँचर</translation>
 <translation id="152892567002884378">आवाज मोठा करा</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, नंतर <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">क्लिपबोर्डवरून आशय पेस्ट करा</translation>
 <translation id="9052808072970550123">पुढील वापरकर्त्यावर स्विच करा</translation>
 <translation id="906458777597946297">विंडो वाढवा</translation>
+<translation id="9091855755813503076">ओळीच्या सुरवातीला जा</translation>
 <translation id="9106898733795143799">पेज आणि वेब ब्राउझर</translation>
 <translation id="9162942292291287644"><ph name="QUERY" /> साठी शोध परिणाम नाहीत</translation>
 <translation id="9179672198516322668">लोकप्रिय शॉर्टकट</translation>
diff --git a/ash/components/strings/ash_components_strings_ms.xtb b/ash/components/strings/ash_components_strings_ms.xtb
index a57ff46..c043f1f 100644
--- a/ash/components/strings/ash_components_strings_ms.xtb
+++ b/ash/components/strings/ash_components_strings_ms.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Cetak halaman semasa anda</translation>
 <translation id="1383876407941801731">Carian</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> atau <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Pergi ke hujung baris</translation>
 <translation id="1510238584712386396">Pelancar</translation>
 <translation id="152892567002884378">Tambah kelantangan</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, kemudian <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Tampal kandungan daripada papan keratan</translation>
 <translation id="9052808072970550123">Beralih kepada pengguna seterusnya</translation>
 <translation id="906458777597946297">Maksimumkan tetingkap</translation>
+<translation id="9091855755813503076">Pergi ke permulaan baris</translation>
 <translation id="9106898733795143799">Halaman &amp; Penyemak Imbas Web</translation>
 <translation id="9162942292291287644">Tiada hasil carian untuk <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Pintasan Popular</translation>
diff --git a/ash/components/strings/ash_components_strings_nl.xtb b/ash/components/strings/ash_components_strings_nl.xtb
index 567836d..a3167f1 100644
--- a/ash/components/strings/ash_components_strings_nl.xtb
+++ b/ash/components/strings/ash_components_strings_nl.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">De huidige pagina afdrukken</translation>
 <translation id="1383876407941801731">Zoeken</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> of <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Naar het einde van de regel gaan</translation>
 <translation id="1510238584712386396">Launcher</translation>
 <translation id="152892567002884378">Volume omhoog</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, en dan <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Content vanaf het klembord plakken</translation>
 <translation id="9052808072970550123">Overschakelen naar de volgende gebruiker</translation>
 <translation id="906458777597946297">Venster maximaliseren</translation>
+<translation id="9091855755813503076">Naar het begin van de regel gaan</translation>
 <translation id="9106898733795143799">Pagina- en webbrowser</translation>
 <translation id="9162942292291287644">Geen zoekresultaat voor <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Populaire sneltoetsen</translation>
diff --git a/ash/components/strings/ash_components_strings_no.xtb b/ash/components/strings/ash_components_strings_no.xtb
index d65a4bc..80e300a 100644
--- a/ash/components/strings/ash_components_strings_no.xtb
+++ b/ash/components/strings/ash_components_strings_no.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Skriv ut den aktive siden</translation>
 <translation id="1383876407941801731">Søk</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> eller <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Gå til slutten av linjen</translation>
 <translation id="1510238584712386396">Appvelger</translation>
 <translation id="152892567002884378">Volum opp</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> og så <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Lim inn innholdet fra utklippstavlen</translation>
 <translation id="9052808072970550123">Bytt til den neste brukeren</translation>
 <translation id="906458777597946297">Maksimerer vinduet</translation>
+<translation id="9091855755813503076">Gå til begynnelsen av linjen</translation>
 <translation id="9106898733795143799">Side og nettleser</translation>
 <translation id="9162942292291287644">Ingen søkeresultater for <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Populære hurtigtaster</translation>
diff --git a/ash/components/strings/ash_components_strings_pl.xtb b/ash/components/strings/ash_components_strings_pl.xtb
index afd2115..5505a07 100644
--- a/ash/components/strings/ash_components_strings_pl.xtb
+++ b/ash/components/strings/ash_components_strings_pl.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Wydrukuj bieżącą stronę</translation>
 <translation id="1383876407941801731">Szukaj</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> lub <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Przejdź na koniec wiersza</translation>
 <translation id="1510238584712386396">Menu z aplikacjami</translation>
 <translation id="152892567002884378">Zwiększ głośność</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, a następnie <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Wklej zawartość schowka</translation>
 <translation id="9052808072970550123">Przełącz do następnego użytkownika</translation>
 <translation id="906458777597946297">Maksymalizuj okno</translation>
+<translation id="9091855755813503076">Przejdź na początek wiersza</translation>
 <translation id="9106898733795143799">Przeglądarka stron i internetu</translation>
 <translation id="9162942292291287644">Brak wyników wyszukiwania dla: <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Popularne skróty</translation>
diff --git a/ash/components/strings/ash_components_strings_pt-BR.xtb b/ash/components/strings/ash_components_strings_pt-BR.xtb
index be8ce1c..dcee650 100644
--- a/ash/components/strings/ash_components_strings_pt-BR.xtb
+++ b/ash/components/strings/ash_components_strings_pt-BR.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Imprimir a página atual</translation>
 <translation id="1383876407941801731">Pesquisar</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> ou <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Ir para o fim da linha</translation>
 <translation id="1510238584712386396">Iniciador</translation>
 <translation id="152892567002884378">Aumentar volume</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> e depois <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Colar conteúdo da área de transferência</translation>
 <translation id="9052808072970550123">Alternar para o próximo usuário</translation>
 <translation id="906458777597946297">Maximizar janela</translation>
+<translation id="9091855755813503076">Ir para o início da linha</translation>
 <translation id="9106898733795143799">Página e navegador da Web</translation>
 <translation id="9162942292291287644">Nenhum resultado da pesquisa para <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Atalhos mais usados</translation>
diff --git a/ash/components/strings/ash_components_strings_pt-PT.xtb b/ash/components/strings/ash_components_strings_pt-PT.xtb
index 05a6db4f..a4a39e2 100644
--- a/ash/components/strings/ash_components_strings_pt-PT.xtb
+++ b/ash/components/strings/ash_components_strings_pt-PT.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Imprimir a página atual</translation>
 <translation id="1383876407941801731">Pesquisar</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> ou <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" />.</translation>
+<translation id="1477442857810932985">Ir para o fim da linha</translation>
 <translation id="1510238584712386396">Iniciador</translation>
 <translation id="152892567002884378">Aumentar o volume</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, em seguida, <ph name="ESC" />.</translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Colar o conteúdo da área de transferência</translation>
 <translation id="9052808072970550123">Mudar para o utilizador seguinte</translation>
 <translation id="906458777597946297">Maximizar janela</translation>
+<translation id="9091855755813503076">Ir para o início da linha</translation>
 <translation id="9106898733795143799">Página e navegador de Internet</translation>
 <translation id="9162942292291287644">Nenhum resultado da pesquisa para <ph name="QUERY" />.</translation>
 <translation id="9179672198516322668">Atalhos populares</translation>
diff --git a/ash/components/strings/ash_components_strings_ro.xtb b/ash/components/strings/ash_components_strings_ro.xtb
index 46b4193..0c2df1d 100644
--- a/ash/components/strings/ash_components_strings_ro.xtb
+++ b/ash/components/strings/ash_components_strings_ro.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Printează pagina curentă</translation>
 <translation id="1383876407941801731">Caută</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> sau <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Treci la sfârșitul rândului</translation>
 <translation id="1510238584712386396">Lansator</translation>
 <translation id="152892567002884378">Mărește volumul</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, apoi <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Inserează conținutul din clipboard</translation>
 <translation id="9052808072970550123">Comută la următorul utilizator</translation>
 <translation id="906458777597946297">Maximizați fereastra</translation>
+<translation id="9091855755813503076">Treci la începutul rândului</translation>
 <translation id="9106898733795143799">Pagina și browserul web</translation>
 <translation id="9162942292291287644">Niciun rezultat al căutării pentru <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Comenzi rapide populare</translation>
diff --git a/ash/components/strings/ash_components_strings_ru.xtb b/ash/components/strings/ash_components_strings_ru.xtb
index 3876fde..be98bac 100644
--- a/ash/components/strings/ash_components_strings_ru.xtb
+++ b/ash/components/strings/ash_components_strings_ru.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Распечатать страницу</translation>
 <translation id="1383876407941801731">Поиск</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> или <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Перейти к концу строки</translation>
 <translation id="1510238584712386396">Панель запуска</translation>
 <translation id="152892567002884378">Увеличить громкость</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, затем <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Вставить содержимое из буфера обмена</translation>
 <translation id="9052808072970550123">Переключиться на следующего пользователя</translation>
 <translation id="906458777597946297">Развернуть окно</translation>
+<translation id="9091855755813503076">Перейти к началу строки</translation>
 <translation id="9106898733795143799">Страница и браузер</translation>
 <translation id="9162942292291287644">По запросу "<ph name="QUERY" />" ничего не найдено</translation>
 <translation id="9179672198516322668">Часто используемые быстрые клавиши</translation>
diff --git a/ash/components/strings/ash_components_strings_sk.xtb b/ash/components/strings/ash_components_strings_sk.xtb
index ce66e61..127fb5b 100644
--- a/ash/components/strings/ash_components_strings_sk.xtb
+++ b/ash/components/strings/ash_components_strings_sk.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Tlač aktuálnej stránky</translation>
 <translation id="1383876407941801731">Vyhľadávanie</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> alebo <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Prejsť na koniec riadka</translation>
 <translation id="1510238584712386396">Spúšťač</translation>
 <translation id="152892567002884378">Zvýšenie hlasitosti</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, potom <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Prilepenie obsahu zo schránky</translation>
 <translation id="9052808072970550123">Prepnutie na ďalšieho používateľa</translation>
 <translation id="906458777597946297">Maximalizovať okno</translation>
+<translation id="9091855755813503076">Prejsť na začiatok riadka</translation>
 <translation id="9106898733795143799">Stránka a webový prehliadač</translation>
 <translation id="9162942292291287644">Žiadne výsledky vyhľadávania na tému <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Obľúbené skratky</translation>
diff --git a/ash/components/strings/ash_components_strings_sl.xtb b/ash/components/strings/ash_components_strings_sl.xtb
index 217fe9d..fa4d663 100644
--- a/ash/components/strings/ash_components_strings_sl.xtb
+++ b/ash/components/strings/ash_components_strings_sl.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Tiskanje trenutne strani</translation>
 <translation id="1383876407941801731">Išči</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /> <ph name="SEPARATOR1" /> <ph name="SHIFT1" /> <ph name="SEPARATOR2" /> <ph name="G" /> ali <ph name="SHIFT2" /> <ph name="SEPARATOR3" /> <ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Pomik na konec vrstice</translation>
 <translation id="1510238584712386396">Zaganjalnik</translation>
 <translation id="152892567002884378">Povečanje glasnosti</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /> <ph name="SEPARATOR1" /> <ph name="ALT" /> <ph name="SEPARATOR2" /> <ph name="L" />, nato <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Lepljenje vsebine iz odložišča</translation>
 <translation id="9052808072970550123">Preklop na naslednjega uporabnika</translation>
 <translation id="906458777597946297">Povečanje okna</translation>
+<translation id="9091855755813503076">Pomik na začetek vrstice</translation>
 <translation id="9106898733795143799">Stran in brskalnik</translation>
 <translation id="9162942292291287644">Ni rezultatov iskanja za poizvedbo <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Priljubljene bližnjice</translation>
diff --git a/ash/components/strings/ash_components_strings_sr.xtb b/ash/components/strings/ash_components_strings_sr.xtb
index 2049758..072c3db 100644
--- a/ash/components/strings/ash_components_strings_sr.xtb
+++ b/ash/components/strings/ash_components_strings_sr.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Штампајте тренутну страницу</translation>
 <translation id="1383876407941801731">Претражи</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> или <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Идите на крај реда</translation>
 <translation id="1510238584712386396">Покретач</translation>
 <translation id="152892567002884378">Појачајте звук</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, па <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Налепите садржај из привремене меморије</translation>
 <translation id="9052808072970550123">Пређите на следећег корисника</translation>
 <translation id="906458777597946297">Повећавање прозора</translation>
+<translation id="9091855755813503076">Идите на почетак реда</translation>
 <translation id="9106898733795143799">Страница и веб-прегледач</translation>
 <translation id="9162942292291287644">Резултати претраге за упит <ph name="QUERY" /> нису пронађени</translation>
 <translation id="9179672198516322668">Популарне пречице</translation>
diff --git a/ash/components/strings/ash_components_strings_sv.xtb b/ash/components/strings/ash_components_strings_sv.xtb
index 4c30bfc..7d8252c 100644
--- a/ash/components/strings/ash_components_strings_sv.xtb
+++ b/ash/components/strings/ash_components_strings_sv.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Skriv ut den aktuella sidan</translation>
 <translation id="1383876407941801731">Sök</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> eller <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Gå till slutet av raden</translation>
 <translation id="1510238584712386396">Startprogram</translation>
 <translation id="152892567002884378">Höj volymen</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, sedan <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Klistra in innehållet i Urklipp</translation>
 <translation id="9052808072970550123">Växla till nästa användare</translation>
 <translation id="906458777597946297">Maximera fönstret</translation>
+<translation id="9091855755813503076">Gå till början av raden</translation>
 <translation id="9106898733795143799">Sidor och webbläsare</translation>
 <translation id="9162942292291287644">Inget sökresultat för <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Populära kortkommandon</translation>
diff --git a/ash/components/strings/ash_components_strings_sw.xtb b/ash/components/strings/ash_components_strings_sw.xtb
index bda8d2c..32183985 100644
--- a/ash/components/strings/ash_components_strings_sw.xtb
+++ b/ash/components/strings/ash_components_strings_sw.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Chapisha ukurasa wa sasa</translation>
 <translation id="1383876407941801731">Tafuta</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> au <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Nenda kwenye mwisho wa mstari</translation>
 <translation id="1510238584712386396">Kizindua</translation>
 <translation id="152892567002884378">Ongeza sauti</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, kisha <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Bandika maudhui kutoka ubao wa kunakili</translation>
 <translation id="9052808072970550123">Nenda kwenye mtumiaji anayefuata</translation>
 <translation id="906458777597946297">Zidisha dirisha</translation>
+<translation id="9091855755813503076">Nenda kwenye mwanzo wa mstari</translation>
 <translation id="9106898733795143799">Kivinjari na Kurasa</translation>
 <translation id="9162942292291287644">Haijapata matokeo yoyote ya utafutaji wa <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Njia Maarufu za Mkato</translation>
diff --git a/ash/components/strings/ash_components_strings_ta.xtb b/ash/components/strings/ash_components_strings_ta.xtb
index b770336..01a1b81 100644
--- a/ash/components/strings/ash_components_strings_ta.xtb
+++ b/ash/components/strings/ash_components_strings_ta.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">உங்கள் தற்போதைய பக்கத்தை அச்சிடும்</translation>
 <translation id="1383876407941801731">தேடல்</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> அல்லது <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">வரியின் இறுதிக்குச் செல்லும்</translation>
 <translation id="1510238584712386396">துவக்கி</translation>
 <translation id="152892567002884378">ஒலியளவை அதிகரிக்கும்</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, பின்னர் <ph name="ESC" />ஐ அழுத்தவும்</translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">கிளிப்போர்டிலிருந்து உள்ளடக்கத்தை ஒட்டும்</translation>
 <translation id="9052808072970550123">அடுத்த பயனருக்குச் செல்லும்</translation>
 <translation id="906458777597946297">சாளரத்தை பெரிதாக்கு</translation>
+<translation id="9091855755813503076">வரியின் தொடக்கத்திற்குச் செல்லும்</translation>
 <translation id="9106898733795143799">பக்கம் &amp; இணைய உலாவி</translation>
 <translation id="9162942292291287644"><ph name="QUERY" />க்குத் தேடல் முடிவு எதுவுமில்லை</translation>
 <translation id="9179672198516322668">பிரபல ஷார்ட்கட்கள்</translation>
diff --git a/ash/components/strings/ash_components_strings_te.xtb b/ash/components/strings/ash_components_strings_te.xtb
index 29f1b4b..ef15290 100644
--- a/ash/components/strings/ash_components_strings_te.xtb
+++ b/ash/components/strings/ash_components_strings_te.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">మీ ప్రస్తుత పేజీని ముద్రించండి</translation>
 <translation id="1383876407941801731">శోధించు</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> లేదా <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">పంక్తి చివరికి వెళ్లు</translation>
 <translation id="1510238584712386396">లాంచర్</translation>
 <translation id="152892567002884378">వాల్యూమ్ పెంచండి</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, ఆపై <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">క్లిప్‌బోర్డ్ నుండి కంటెంట్‌ను అతికించండి</translation>
 <translation id="9052808072970550123">తదుపరి వినియోగదారుకు మారండి</translation>
 <translation id="906458777597946297">విండోను గరిష్టీకరించు</translation>
+<translation id="9091855755813503076">పంక్తి ప్రారంభానికి వెళ్లు</translation>
 <translation id="9106898733795143799">పేజీ &amp; వెబ్ బ్రౌజర్</translation>
 <translation id="9162942292291287644"><ph name="QUERY" /> కోసం శోధన ఫలితం లేదు</translation>
 <translation id="9179672198516322668">జనాదరణ పొందిన షార్ట్‌కట్‌లు</translation>
diff --git a/ash/components/strings/ash_components_strings_th.xtb b/ash/components/strings/ash_components_strings_th.xtb
index 7ae4fdd..a1eabbc 100644
--- a/ash/components/strings/ash_components_strings_th.xtb
+++ b/ash/components/strings/ash_components_strings_th.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">พิมพ์หน้าเว็บปัจจุบัน</translation>
 <translation id="1383876407941801731">ค้นหา</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> หรือ <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">ไปที่ท้ายบรรทัด</translation>
 <translation id="1510238584712386396">ตัวเรียกใช้งาน</translation>
 <translation id="152892567002884378">เพิ่มระดับเสียง</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> แล้วกด <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">วางเนื้อหาจากคลิปบอร์ด</translation>
 <translation id="9052808072970550123">เปลี่ยนเป็นผู้ใช้ถัดไป</translation>
 <translation id="906458777597946297">ขยายหน้าต่างเต็มหน้าจอ</translation>
+<translation id="9091855755813503076">ไปที่จุดเริ่มต้นของบรรทัด</translation>
 <translation id="9106898733795143799">หน้าและเว็บเบราว์เซอร์</translation>
 <translation id="9162942292291287644">ไม่พบผลการค้นหา <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">แป้นพิมพ์ลัดยอดนิยม</translation>
diff --git a/ash/components/strings/ash_components_strings_tr.xtb b/ash/components/strings/ash_components_strings_tr.xtb
index cdf4a0e..10fefb0 100644
--- a/ash/components/strings/ash_components_strings_tr.xtb
+++ b/ash/components/strings/ash_components_strings_tr.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Geçerli sayfanızı yazdırır</translation>
 <translation id="1383876407941801731">Ara</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> veya <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Satırın sonuna gider</translation>
 <translation id="1510238584712386396">Başlatıcı</translation>
 <translation id="152892567002884378">Sesi açar</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, daha sonra <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Panodaki içeriği yapıştırır</translation>
 <translation id="9052808072970550123">Sonraki kullanıcıya geçer</translation>
 <translation id="906458777597946297">Pencereyi ekranı kaplayacak şekilde büyüt</translation>
+<translation id="9091855755813503076">Satırın başına gider</translation>
 <translation id="9106898733795143799">Sayfa ve Web Tarayıcısı</translation>
 <translation id="9162942292291287644"><ph name="QUERY" /> için arama sonucu yok</translation>
 <translation id="9179672198516322668">Popüler Kısayollar</translation>
diff --git a/ash/components/strings/ash_components_strings_uk.xtb b/ash/components/strings/ash_components_strings_uk.xtb
index a78bb8c..c5ec1785 100644
--- a/ash/components/strings/ash_components_strings_uk.xtb
+++ b/ash/components/strings/ash_components_strings_uk.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">Друкувати поточну сторінку</translation>
 <translation id="1383876407941801731">Пошук</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> або <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Перейти в кінець рядка</translation>
 <translation id="1510238584712386396">Панель запуску</translation>
 <translation id="152892567002884378">Збільшити гучність</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, а тоді <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Вставити вміст із буфера обміну</translation>
 <translation id="9052808072970550123">Перейти в наступний профіль користувача</translation>
 <translation id="906458777597946297">Розгорнути вікно</translation>
+<translation id="9091855755813503076">Перейти на початок рядка</translation>
 <translation id="9106898733795143799">Сторінка та веб-переглядач</translation>
 <translation id="9162942292291287644">Немає результатів пошуку за запитом "<ph name="QUERY" />"</translation>
 <translation id="9179672198516322668">Популярні комбінації клавіш</translation>
diff --git a/ash/components/strings/ash_components_strings_vi.xtb b/ash/components/strings/ash_components_strings_vi.xtb
index 73e0c08..5e26541 100644
--- a/ash/components/strings/ash_components_strings_vi.xtb
+++ b/ash/components/strings/ash_components_strings_vi.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">In trang hiện tại</translation>
 <translation id="1383876407941801731">Tìm kiếm</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> hoặc <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">Chuyển đến cuối dòng</translation>
 <translation id="1510238584712386396">Trình chạy</translation>
 <translation id="152892567002884378">Tăng âm lượng</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />, rồi đến <ph name="ESC" /></translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">Dán nội dung từ khay nhớ tạm</translation>
 <translation id="9052808072970550123">Chuyển sang người dùng tiếp theo</translation>
 <translation id="906458777597946297">Phóng to cửa sổ</translation>
+<translation id="9091855755813503076">Chuyển đến đầu dòng</translation>
 <translation id="9106898733795143799">Trang và trình duyệt web</translation>
 <translation id="9162942292291287644">Không có kết quả tìm kiếm nào cho <ph name="QUERY" /></translation>
 <translation id="9179672198516322668">Các phím tắt thông dụng</translation>
diff --git a/ash/components/strings/ash_components_strings_zh-CN.xtb b/ash/components/strings/ash_components_strings_zh-CN.xtb
index 09f215c..e81dc46 100644
--- a/ash/components/strings/ash_components_strings_zh-CN.xtb
+++ b/ash/components/strings/ash_components_strings_zh-CN.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">打印当前网页</translation>
 <translation id="1383876407941801731">搜索</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> 或 <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /></translation>
+<translation id="1477442857810932985">转至行末</translation>
 <translation id="1510238584712386396">启动器</translation>
 <translation id="152892567002884378">调高音量</translation>
 <translation id="1560480564179555003"><ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" />,然后按 <ph name="ESC" /> 键</translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">粘贴剪贴板中的内容</translation>
 <translation id="9052808072970550123">切换到下一位用户</translation>
 <translation id="906458777597946297">最大化窗口</translation>
+<translation id="9091855755813503076">转至行首</translation>
 <translation id="9106898733795143799">网页和网络浏览器</translation>
 <translation id="9162942292291287644">找不到与“<ph name="QUERY" />”相符的搜索结果</translation>
 <translation id="9179672198516322668">常用快捷键</translation>
diff --git a/ash/components/strings/ash_components_strings_zh-TW.xtb b/ash/components/strings/ash_components_strings_zh-TW.xtb
index 337ecbb..b1abcaf 100644
--- a/ash/components/strings/ash_components_strings_zh-TW.xtb
+++ b/ash/components/strings/ash_components_strings_zh-TW.xtb
@@ -11,6 +11,7 @@
 <translation id="1299858300159559687">列印目前網頁</translation>
 <translation id="1383876407941801731">搜尋</translation>
 <translation id="1454364489140280055"><ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT1" /><ph name="SEPARATOR2" /><ph name="G" /> 鍵或 <ph name="SHIFT2" /><ph name="SEPARATOR3" /><ph name="ENTER" /> 鍵</translation>
+<translation id="1477442857810932985">移到行尾</translation>
 <translation id="1510238584712386396">啟動器</translation>
 <translation id="152892567002884378">調高音量</translation>
 <translation id="1560480564179555003">按下 <ph name="SHIFT" /><ph name="SEPARATOR1" /><ph name="ALT" /><ph name="SEPARATOR2" /><ph name="L" /> 鍵,然後按下 <ph name="ESC" /> 鍵</translation>
@@ -191,6 +192,7 @@
 <translation id="9041599225465145264">貼上剪貼簿中的內容</translation>
 <translation id="9052808072970550123">切換至下一個使用者</translation>
 <translation id="906458777597946297">將視窗放到最大</translation>
+<translation id="9091855755813503076">移到行首</translation>
 <translation id="9106898733795143799">網頁與網路瀏覽器</translation>
 <translation id="9162942292291287644">找不到與「<ph name="QUERY" />」相符的搜尋結果</translation>
 <translation id="9179672198516322668">常用快速鍵</translation>
diff --git a/ash/dbus/OWNERS b/ash/dbus/OWNERS
new file mode 100644
index 0000000..f3164c9
--- /dev/null
+++ b/ash/dbus/OWNERS
@@ -0,0 +1,3 @@
+file://chromeos/dbus/OWNERS
+per-file org.chromium.*.conf=set noparent
+per-file org.chromium.*.conf=file://chromeos/SECURITY_OWNERS
diff --git a/ash/detachable_base/detachable_base_notification_controller.cc b/ash/detachable_base/detachable_base_notification_controller.cc
index b7b81f5..067341d 100644
--- a/ash/detachable_base/detachable_base_notification_controller.cc
+++ b/ash/detachable_base/detachable_base_notification_controller.cc
@@ -9,6 +9,7 @@
 
 #include "ash/detachable_base/detachable_base_handler.h"
 #include "ash/detachable_base/detachable_base_pairing_status.h"
+#include "ash/public/cpp/notification_utils.h"
 #include "ash/public/cpp/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
@@ -64,12 +65,12 @@
       IDS_ASH_DETACHABLE_BASE_NOTIFICATION_UPDATE_NEEDED_MESSAGE);
 
   std::unique_ptr<message_center::Notification> notification =
-      message_center::Notification::CreateSystemNotification(
+      ash::CreateSystemNotification(
           message_center::NOTIFICATION_TYPE_SIMPLE,
           kBaseRequiresUpdateNotificationId, title, message, base::string16(),
           GURL(),
           message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT,
+              message_center::NotifierType::SYSTEM_COMPONENT,
               kDetachableBaseNotifierId),
           message_center::RichNotificationData(), nullptr,
           kNotificationWarningIcon,
@@ -140,11 +141,11 @@
       IDS_ASH_DETACHABLE_BASE_NOTIFICATION_DEVICE_CHANGED_MESSAGE);
 
   std::unique_ptr<message_center::Notification> notification =
-      message_center::Notification::CreateSystemNotification(
+      ash::CreateSystemNotification(
           message_center::NOTIFICATION_TYPE_SIMPLE, kBaseChangedNotificationId,
           title, message, base::string16(), GURL(),
           message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT,
+              message_center::NotifierType::SYSTEM_COMPONENT,
               kDetachableBaseNotifierId),
           options, nullptr, kNotificationWarningIcon,
           message_center::SystemNotificationWarningLevel::CRITICAL_WARNING);
diff --git a/ash/display/cros_display_config.cc b/ash/display/cros_display_config.cc
index 849879f..52fd730 100644
--- a/ash/display/cros_display_config.cc
+++ b/ash/display/cros_display_config.cc
@@ -618,8 +618,10 @@
     primary_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
   } else {
     displays = display_manager->software_mirroring_display_list();
-    primary_id =
-        display_manager->GetPrimaryMirroringDisplayForUnifiedDesktop()->id();
+    primary_id = Shell::Get()
+                     ->display_configuration_controller()
+                     ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                     .id();
   }
 
   for (const display::Display& display : displays)
diff --git a/ash/display/display_configuration_controller.cc b/ash/display/display_configuration_controller.cc
index 223e6b0..2cb90d5 100644
--- a/ash/display/display_configuration_controller.cc
+++ b/ash/display/display_configuration_controller.cc
@@ -7,7 +7,10 @@
 #include "ash/display/display_animator.h"
 #include "ash/display/display_util.h"
 #include "ash/display/window_tree_host_manager.h"
+#include "ash/public/cpp/shelf_types.h"
+#include "ash/root_window_controller.h"
 #include "ash/rotator/screen_rotation_animator.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "base/time/time.h"
@@ -19,6 +22,8 @@
 
 DEFINE_UI_CLASS_PROPERTY_TYPE(ash::ScreenRotationAnimator*);
 
+namespace ash {
+
 namespace {
 
 // Specifies how long the display change should have been disabled
@@ -39,9 +44,26 @@
 
 bool g_disable_animator_for_test = false;
 
-}  // namespace
+display::DisplayPositionInUnifiedMatrix GetUnifiedModeShelfCellPosition() {
+  const ShelfAlignment alignment =
+      Shell::GetPrimaryRootWindowController()->shelf()->alignment();
+  switch (alignment) {
+    case SHELF_ALIGNMENT_BOTTOM:
+    case SHELF_ALIGNMENT_BOTTOM_LOCKED:
+      return display::DisplayPositionInUnifiedMatrix::kBottomLeft;
 
-namespace ash {
+    case SHELF_ALIGNMENT_LEFT:
+      return display::DisplayPositionInUnifiedMatrix::kTopLeft;
+
+    case SHELF_ALIGNMENT_RIGHT:
+      return display::DisplayPositionInUnifiedMatrix::kTopRight;
+  }
+
+  NOTREACHED();
+  return display::DisplayPositionInUnifiedMatrix::kBottomLeft;
+}
+
+}  // namespace
 
 class DisplayConfigurationController::DisplayChangeLimiter {
  public:
@@ -177,6 +199,15 @@
   }
 }
 
+display::Display
+DisplayConfigurationController::GetPrimaryMirroringDisplayForUnifiedDesktop()
+    const {
+  DCHECK(display_manager_->IsInUnifiedMode());
+
+  return display_manager_->GetMirroringDisplayForUnifiedDesktop(
+      GetUnifiedModeShelfCellPosition());
+}
+
 void DisplayConfigurationController::OnDisplayConfigurationChanged() {
   // TODO(oshima): Stop all animations.
   SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs);
diff --git a/ash/display/display_configuration_controller.h b/ash/display/display_configuration_controller.h
index 0a1e999..cfd3949 100644
--- a/ash/display/display_configuration_controller.h
+++ b/ash/display/display_configuration_controller.h
@@ -75,6 +75,16 @@
   // called within the throttle time.
   void SetPrimaryDisplayId(int64_t display_id, bool throttle);
 
+  // In Unified Desktop mode, we consider the display in which the shelf will be
+  // placed to be the "primary mirroring display". Note that this is different
+  // from the "normal" primary display, which is just the single unified display
+  // in unified mode. This display will be:
+  //   - The bottom-left in the matrix if the shelf alignment is "bottom",
+  //   - The top-left in the matrix if the shelf alignment is "left",
+  //   - The top-right in the matrix if the shelf alignment is "right".
+  // This should only be called when Unified Desktop mode is active.
+  display::Display GetPrimaryMirroringDisplayForUnifiedDesktop() const;
+
   // WindowTreeHostManager::Observer
   void OnDisplayConfigurationChanged() override;
 
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 276afb4..b30f9b1 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -15,7 +15,9 @@
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/ash_switches.h"
+#include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/test/ash_test_base.h"
@@ -2718,10 +2720,12 @@
     display_manager()->SetUnifiedDesktopMatrix(matrix);
     // 500 + 400 * 200 / 300 ~= 766.
     EXPECT_EQ(gfx::Size(400, 766), screen->GetPrimaryDisplay().size());
-    // Display in top-left cell is considered primary.
-    EXPECT_EQ(
-        list[0],
-        display_manager()->GetPrimaryMirroringDisplayForUnifiedDesktop()->id());
+    // Default shelf alignment is bottom. Display in bottom-left cell is
+    // considered the primary mirroring display.
+    EXPECT_EQ(list[1], Shell::Get()
+                           ->display_configuration_controller()
+                           ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                           .id());
 
     // Validate display rows and max heights.
     EXPECT_EQ(0, display_manager()->GetMirroringDisplayRowIndexInUnifiedMatrix(
@@ -2747,10 +2751,11 @@
     // 200 + 300 * 500 / 400 ~= 574 (Note that we actually scale the max unified
     // bounds).
     EXPECT_EQ(gfx::Size(300, 574), screen->GetPrimaryDisplay().size());
-    // Display in top-left cell is considered primary.
-    EXPECT_EQ(
-        list[1],
-        display_manager()->GetPrimaryMirroringDisplayForUnifiedDesktop()->id());
+    // Display in bottom-left cell is considered primary.
+    EXPECT_EQ(list[0], Shell::Get()
+                           ->display_configuration_controller()
+                           ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                           .id());
 
     // Validate display rows and max heights.
     EXPECT_EQ(1, display_manager()->GetMirroringDisplayRowIndexInUnifiedMatrix(
@@ -2781,10 +2786,11 @@
                                                            list[1]);
     display_manager()->OnNativeDisplaysChanged(display_info_list);
     EXPECT_EQ(gfx::Size(300, 574), screen->GetPrimaryDisplay().size());
-    // Display in top-left cell is considered primary.
-    EXPECT_EQ(
-        list[0],
-        display_manager()->GetPrimaryMirroringDisplayForUnifiedDesktop()->id());
+    // Display in bottom-left cell is considered primary.
+    EXPECT_EQ(list[1], Shell::Get()
+                           ->display_configuration_controller()
+                           ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                           .id());
 
     // Validate display rows and max heights.
     EXPECT_EQ(0, display_manager()->GetMirroringDisplayRowIndexInUnifiedMatrix(
@@ -2820,10 +2826,11 @@
     matrix[2].emplace_back(list[2]);
     display_manager()->SetUnifiedDesktopMatrix(matrix);
     EXPECT_EQ(gfx::Size(500, 1225), screen->GetPrimaryDisplay().size());
-    // Display in top-left cell is considered primary.
-    EXPECT_EQ(
-        list[0],
-        display_manager()->GetPrimaryMirroringDisplayForUnifiedDesktop()->id());
+    // Display in bottom-left cell is considered primary.
+    EXPECT_EQ(list[2], Shell::Get()
+                           ->display_configuration_controller()
+                           ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                           .id());
 
     // Validate display rows and max heights.
     EXPECT_EQ(0, display_manager()->GetMirroringDisplayRowIndexInUnifiedMatrix(
@@ -2851,10 +2858,11 @@
     matrix[2].emplace_back(list[2]);
     display_manager()->SetUnifiedDesktopMatrix(matrix);
     EXPECT_EQ(gfx::Size(400, 980), screen->GetPrimaryDisplay().size());
-    // Display in top-left cell is considered primary.
-    EXPECT_EQ(
-        list[1],
-        display_manager()->GetPrimaryMirroringDisplayForUnifiedDesktop()->id());
+    // Display in bottom-left cell is considered primary.
+    EXPECT_EQ(list[2], Shell::Get()
+                           ->display_configuration_controller()
+                           ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                           .id());
 
     // Validate display rows and max heights.
     EXPECT_EQ(1, display_manager()->GetMirroringDisplayRowIndexInUnifiedMatrix(
@@ -2892,10 +2900,16 @@
   matrix[1].emplace_back(list[3]);
   display_manager()->SetUnifiedDesktopMatrix(matrix);
   EXPECT_EQ(gfx::Size(739, 933), screen->GetPrimaryDisplay().size());
-  // Display in top-left cell is considered primary.
-  EXPECT_EQ(
-      list[0],
-      display_manager()->GetPrimaryMirroringDisplayForUnifiedDesktop()->id());
+
+  // Default shelf alignment is bottom.
+  Shelf* shelf = Shell::GetPrimaryRootWindowController()->shelf();
+  EXPECT_EQ(shelf->alignment(), SHELF_ALIGNMENT_BOTTOM);
+
+  // Display in bottom-left cell is considered the primary mirroring display.
+  EXPECT_EQ(list[2], Shell::Get()
+                         ->display_configuration_controller()
+                         ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                         .id());
 
   // Validate display rows and max heights.
   EXPECT_EQ(0, display_manager()->GetMirroringDisplayRowIndexInUnifiedMatrix(
@@ -2909,6 +2923,22 @@
   EXPECT_EQ(300, display_manager()->GetUnifiedDesktopRowMaxHeight(0));
   EXPECT_EQ(633, display_manager()->GetUnifiedDesktopRowMaxHeight(1));
   EXPECT_FALSE(OverlappingMirroringDisplaysExist());
+
+  // Change the shelf alignment to left, and expect that the primary mirroring
+  // display in the top-left display in the matrix.
+  shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
+  EXPECT_EQ(list[0], Shell::Get()
+                         ->display_configuration_controller()
+                         ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                         .id());
+
+  // Change the shelf alignment to right, and expect that the primary mirroring
+  // display in the top-right display in the matrix.
+  shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
+  EXPECT_EQ(list[1], Shell::Get()
+                         ->display_configuration_controller()
+                         ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                         .id());
 }
 
 TEST_F(DisplayManagerTest, UnifiedDesktopGridLayout3x2) {
@@ -2935,10 +2965,16 @@
   matrix[2].emplace_back(list[5]);
   display_manager()->SetUnifiedDesktopMatrix(matrix);
   EXPECT_EQ(gfx::Size(739, 1108), screen->GetPrimaryDisplay().size());
-  // Display in top-left cell is considered primary.
-  EXPECT_EQ(
-      list[0],
-      display_manager()->GetPrimaryMirroringDisplayForUnifiedDesktop()->id());
+
+  // Default shelf alignment is bottom.
+  Shelf* shelf = Shell::GetPrimaryRootWindowController()->shelf();
+  EXPECT_EQ(shelf->alignment(), SHELF_ALIGNMENT_BOTTOM);
+
+  // Display in bottom-left cell is considered the primary mirroring display.
+  EXPECT_EQ(list[4], Shell::Get()
+                         ->display_configuration_controller()
+                         ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                         .id());
 
   // Validate display rows and max heights.
   EXPECT_EQ(0, display_manager()->GetMirroringDisplayRowIndexInUnifiedMatrix(
@@ -2957,6 +2993,22 @@
   EXPECT_EQ(633, display_manager()->GetUnifiedDesktopRowMaxHeight(1));
   EXPECT_EQ(175, display_manager()->GetUnifiedDesktopRowMaxHeight(2));
   EXPECT_FALSE(OverlappingMirroringDisplaysExist());
+
+  // Change the shelf alignment to left, and expect that the primary mirroring
+  // display in the top-left display in the matrix.
+  shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
+  EXPECT_EQ(list[0], Shell::Get()
+                         ->display_configuration_controller()
+                         ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                         .id());
+
+  // Change the shelf alignment to right, and expect that the primary mirroring
+  // display in the top-right display in the matrix.
+  shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
+  EXPECT_EQ(list[1], Shell::Get()
+                         ->display_configuration_controller()
+                         ->GetPrimaryMirroringDisplayForUnifiedDesktop()
+                         .id());
 }
 
 TEST_F(DisplayManagerTest, DockMode) {
diff --git a/ash/display/display_util.cc b/ash/display/display_util.cc
index 3e2d26c..22f8bb3 100644
--- a/ash/display/display_util.cc
+++ b/ash/display/display_util.cc
@@ -13,6 +13,7 @@
 #include "ash/display/unified_mouse_warp_controller.h"
 #include "ash/host/ash_window_tree_host.h"
 #include "ash/new_window_controller.h"
+#include "ash/public/cpp/notification_utils.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -152,14 +153,14 @@
   }
 
   std::unique_ptr<message_center::Notification> notification =
-      message_center::Notification::CreateSystemNotification(
+      ash::CreateSystemNotification(
           message_center::NOTIFICATION_TYPE_SIMPLE, kDisplayErrorNotificationId,
           base::string16(),  // title
           message,
           base::string16(),  // display_source
           GURL(),
           message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT,
+              message_center::NotifierType::SYSTEM_COMPONENT,
               kNotifierDisplayError),
           data,
           base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
diff --git a/ash/display/mirror_window_controller.cc b/ash/display/mirror_window_controller.cc
index fca496d..cd62c8b 100644
--- a/ash/display/mirror_window_controller.cc
+++ b/ash/display/mirror_window_controller.cc
@@ -18,6 +18,8 @@
 #include "ash/window_factory.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/viz/common/features.h"
+#include "components/viz/common/surfaces/surface_id.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window_delegate.h"
@@ -158,6 +160,8 @@
 
   multi_display_mode_ = GetCurrentMultiDisplayMode();
   reflecting_source_id_ = GetCurrentReflectingSourceId();
+  viz::SurfaceId reflecting_surface_id =
+      Shell::GetRootWindowForDisplayId(reflecting_source_id_)->GetSurfaceId();
 
   for (const display::ManagedDisplayInfo& display_info : display_info_list) {
     std::unique_ptr<RootWindowTransformer> transformer;
@@ -220,18 +224,20 @@
       mirror_window->Init(ui::LAYER_SOLID_COLOR);
       host->window()->AddChild(mirror_window);
       host_info->ash_host->SetRootWindowTransformer(std::move(transformer));
-      mirror_window->SetBounds(host->window()->bounds());
-      mirror_window->Show();
       // The accelerated widget is created synchronously.
       DCHECK_NE(gfx::kNullAcceleratedWidget, host->GetAcceleratedWidget());
-      if (reflector_) {
-        reflector_->AddMirroringLayer(mirror_window->layer());
-      } else if (GetContextFactoryPrivate()) {
-        reflector_ = GetContextFactoryPrivate()->CreateReflector(
-            Shell::GetRootWindowForDisplayId(reflecting_source_id_)
-                ->GetHost()
-                ->compositor(),
-            mirror_window->layer());
+      if (!base::FeatureList::IsEnabled(features::kVizDisplayCompositor)) {
+        mirror_window->SetBounds(host->window()->bounds());
+        mirror_window->Show();
+        if (reflector_) {
+          reflector_->AddMirroringLayer(mirror_window->layer());
+        } else if (GetContextFactoryPrivate()) {
+          reflector_ = GetContextFactoryPrivate()->CreateReflector(
+              Shell::GetRootWindowForDisplayId(reflecting_source_id_)
+                  ->GetHost()
+                  ->compositor(),
+              mirror_window->layer());
+        }
       }
     } else {
       AshWindowTreeHost* ash_host =
@@ -241,6 +247,22 @@
       ash_host->SetRootWindowTransformer(std::move(transformer));
       host->SetBoundsInPixels(display_info.bounds_in_native());
     }
+
+    if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor)) {
+      // |mirror_size| is the size of the mirror source in physical pixels.
+      // The RootWindowTransformer corrects the scale of the mirrored display
+      // and the location of input events.
+      gfx::Size mirror_size =
+          display_manager->GetDisplayInfo(reflecting_source_id_)
+              .bounds_in_native()
+              .size();
+      aura::Window* mirror_window =
+          mirroring_host_info_map_[display_info.id()]->mirror_window;
+      mirror_window->SetBounds(gfx::Rect(mirror_size));
+      mirror_window->Show();
+      mirror_window->layer()->SetShowReflectedSurface(reflecting_surface_id,
+                                                      mirror_size);
+    }
   }
 
   // Deleting WTHs for disconnected displays.
diff --git a/ash/display/mirror_window_controller_unittest.cc b/ash/display/mirror_window_controller_unittest.cc
index 6f7d80a..7477f7e 100644
--- a/ash/display/mirror_window_controller_unittest.cc
+++ b/ash/display/mirror_window_controller_unittest.cc
@@ -11,6 +11,8 @@
 #include "ash/wm/cursor_manager_test_api.h"
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/viz/common/features.h"
 #include "ui/aura/env.h"
 #include "ui/aura/test/test_window_delegate.h"
 #include "ui/aura/test/test_windows.h"
@@ -26,10 +28,12 @@
 
 namespace {
 display::ManagedDisplayInfo CreateDisplayInfo(int64_t id,
-                                              const gfx::Rect& bounds) {
+                                              const gfx::Rect& bounds,
+                                              float scale = 1.f) {
   display::ManagedDisplayInfo info(
       id, base::StringPrintf("x-%d", static_cast<int>(id)), false);
   info.SetBounds(bounds);
+  info.set_device_scale_factor(scale);
   return info;
 }
 
@@ -50,24 +54,26 @@
  private:
   DISALLOW_COPY_AND_ASSIGN(MirrorOnBootTest);
 };
-}
 
-using MirrorWindowControllerTest = AshTestBase;
-
-class MirrorWindowControllerTestDisableMultiMirroring : public AshTestBase {
+class MirrorUsingSurfaceLayersTest : public AshTestBase {
  public:
-  MirrorWindowControllerTestDisableMultiMirroring() = default;
-  ~MirrorWindowControllerTestDisableMultiMirroring() override = default;
+  MirrorUsingSurfaceLayersTest() = default;
+  ~MirrorUsingSurfaceLayersTest() override = default;
 
   void SetUp() override {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        ::switches::kDisableMultiMirroring);
+    scoped_feature_list_.InitWithFeatures({features::kVizDisplayCompositor},
+                                          {});
     AshTestBase::SetUp();
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(MirrorWindowControllerTestDisableMultiMirroring);
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(MirrorUsingSurfaceLayersTest);
 };
+}  // namespace
+
+using MirrorWindowControllerTest = AshTestBase;
 
 // Make sure that the compositor based mirroring can switch
 // from/to dock mode.
@@ -91,7 +97,7 @@
   EXPECT_EQ(internal_id, internal_display_id);
 
   display_manager()->SetMirrorMode(display::MirrorMode::kNormal, base::nullopt);
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1U, display_manager()->GetNumDisplays());
   EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
   EXPECT_EQ(external_id,
@@ -123,4 +129,37 @@
   EXPECT_EQ(1U, test_api.GetHosts().size());
 }
 
+// Test that the mirror window matches the size of the host display.
+TEST_F(MirrorUsingSurfaceLayersTest, MirrorSize) {
+  const int64_t primary_id = 1;
+  const int64_t mirror_id = 2;
+
+  // Run the test with and without display scaling.
+  int scale_factors[] = {1, 2};
+  for (int scale : scale_factors) {
+    const display::ManagedDisplayInfo primary_display_info =
+        CreateDisplayInfo(primary_id, gfx::Rect(0, 0, 400, 400), scale);
+    const display::ManagedDisplayInfo mirror_display_info =
+        CreateDisplayInfo(mirror_id, gfx::Rect(400, 0, 600, 600), scale);
+    std::vector<display::ManagedDisplayInfo> display_info_list = {
+        primary_display_info, mirror_display_info};
+
+    // Start software mirroring.
+    display_manager()->OnNativeDisplaysChanged(display_info_list);
+    display_manager()->SetMirrorMode(display::MirrorMode::kNormal,
+                                     base::nullopt);
+    base::RunLoop().RunUntilIdle();
+    EXPECT_EQ(1U, display_manager()->GetNumDisplays());
+    EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
+
+    // Check the size of the mirror window.
+    const display::Display& primary_display =
+        display_manager()->GetDisplayForId(primary_id);
+    aura::Window* root_window = Shell::GetRootWindowForDisplayId(mirror_id);
+    aura::Window* mirror_window = root_window->children()[0];
+    EXPECT_EQ(primary_display.GetSizeInPixel(), root_window->bounds().size());
+    EXPECT_EQ(primary_display.GetSizeInPixel(), mirror_window->bounds().size());
+  }
+}
+
 }  // namespace ash
diff --git a/ash/display/resolution_notification_controller.cc b/ash/display/resolution_notification_controller.cc
index 1a1fadd..b5a0355 100644
--- a/ash/display/resolution_notification_controller.cc
+++ b/ash/display/resolution_notification_controller.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/public/cpp/notification_utils.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
@@ -220,20 +221,18 @@
                 base::UTF8ToUTF16(
                     change_info_->current_resolution.size().ToString()));
 
-  std::unique_ptr<Notification> notification =
-      Notification::CreateSystemNotification(
-          message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, message,
-          timeout_message,
-          base::string16(),  // display_source
-          GURL(),
-          message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT,
-              kNotifierDisplayResolutionChange),
-          data,
-          base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
-              weak_factory_.GetWeakPtr()),
-          kNotificationScreenIcon,
-          message_center::SystemNotificationWarningLevel::NORMAL);
+  std::unique_ptr<Notification> notification = ash::CreateSystemNotification(
+      message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, message,
+      timeout_message,
+      base::string16(),  // display_source
+      GURL(),
+      message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
+                                 kNotifierDisplayResolutionChange),
+      data,
+      base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
+          weak_factory_.GetWeakPtr()),
+      kNotificationScreenIcon,
+      message_center::SystemNotificationWarningLevel::NORMAL);
   notification->set_priority(message_center::SYSTEM_PRIORITY);
 
   message_center->AddNotification(std::move(notification));
diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc
index a4d9463..61d5943 100644
--- a/ash/extended_desktop_unittest.cc
+++ b/ash/extended_desktop_unittest.cc
@@ -7,7 +7,6 @@
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_test_helper.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/window_factory.h"
diff --git a/ash/focus_cycler_unittest.cc b/ash/focus_cycler_unittest.cc
index ef32f00..1638d2b1 100644
--- a/ash/focus_cycler_unittest.cc
+++ b/ash/focus_cycler_unittest.cc
@@ -11,7 +11,6 @@
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_delegate.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/test/test_windows.h"
diff --git a/ash/host/ash_window_tree_host_platform.cc b/ash/host/ash_window_tree_host_platform.cc
index b5f7d96..903b733 100644
--- a/ash/host/ash_window_tree_host_platform.cc
+++ b/ash/host/ash_window_tree_host_platform.cc
@@ -175,10 +175,9 @@
 
 void AshWindowTreeHostPlatform::SetBoundsInPixels(
     const gfx::Rect& bounds,
-    const viz::LocalSurfaceId& local_surface_id,
-    base::TimeTicks allocation_time) {
-  WindowTreeHostPlatform::SetBoundsInPixels(bounds, local_surface_id,
-                                            allocation_time);
+    const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) {
+  WindowTreeHostPlatform::SetBoundsInPixels(bounds,
+                                            local_surface_id_allocation);
   ConfineCursorToRootWindow();
 }
 
diff --git a/ash/host/ash_window_tree_host_platform.h b/ash/host/ash_window_tree_host_platform.h
index 9f1ad01..243ff47 100644
--- a/ash/host/ash_window_tree_host_platform.h
+++ b/ash/host/ash_window_tree_host_platform.h
@@ -66,8 +66,8 @@
       const gfx::Size& host_size_in_pixels) const override;
   void OnCursorVisibilityChangedNative(bool show) override;
   void SetBoundsInPixels(const gfx::Rect& bounds,
-                         const viz::LocalSurfaceId& local_surface_id,
-                         base::TimeTicks allocation_time) override;
+                         const viz::LocalSurfaceIdAllocation&
+                             local_surface_id_allocation) override;
   void DispatchEvent(ui::Event* event) override;
   bool ShouldSendKeyEventToIme() override;
 
diff --git a/ash/host/ash_window_tree_host_unified.cc b/ash/host/ash_window_tree_host_unified.cc
index 5e796fc..c4d4921 100644
--- a/ash/host/ash_window_tree_host_unified.cc
+++ b/ash/host/ash_window_tree_host_unified.cc
@@ -94,10 +94,9 @@
 
 void AshWindowTreeHostUnified::SetBoundsInPixels(
     const gfx::Rect& bounds,
-    const viz::LocalSurfaceId& local_surface_id,
-    base::TimeTicks allocation_time) {
-  AshWindowTreeHostPlatform::SetBoundsInPixels(bounds, local_surface_id,
-                                               allocation_time);
+    const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) {
+  AshWindowTreeHostPlatform::SetBoundsInPixels(bounds,
+                                               local_surface_id_allocation);
   OnHostResizedInPixels(bounds.size());
 }
 
diff --git a/ash/host/ash_window_tree_host_unified.h b/ash/host/ash_window_tree_host_unified.h
index f3d89e1..5d8b1bcc 100644
--- a/ash/host/ash_window_tree_host_unified.h
+++ b/ash/host/ash_window_tree_host_unified.h
@@ -32,8 +32,8 @@
 
   // aura::WindowTreeHost:
   void SetBoundsInPixels(const gfx::Rect& bounds,
-                         const viz::LocalSurfaceId& local_surface_id,
-                         base::TimeTicks allocation_time) override;
+                         const viz::LocalSurfaceIdAllocation&
+                             local_surface_id_allocation) override;
   void SetCursorNative(gfx::NativeCursor cursor) override;
   void OnCursorVisibilityChangedNative(bool show) override;
 
diff --git a/ash/keyboard/arc/arc_input_method_surface_manager_unittest.cc b/ash/keyboard/arc/arc_input_method_surface_manager_unittest.cc
index 03d4e1b..643d1d5 100644
--- a/ash/keyboard/arc/arc_input_method_surface_manager_unittest.cc
+++ b/ash/keyboard/arc/arc_input_method_surface_manager_unittest.cc
@@ -10,6 +10,7 @@
 #include "components/exo/input_method_surface.h"
 #include "components/exo/surface.h"
 #include "components/exo/wm_helper.h"
+#include "components/exo/wm_helper_chromeos.h"
 #include "ui/aura/env.h"
 
 namespace ash {
@@ -42,7 +43,8 @@
 
   void SetUp() override {
     AshTestBase::SetUp();
-    wm_helper_ = std::make_unique<exo::WMHelper>(Shell::Get()->aura_env());
+    wm_helper_ =
+        std::make_unique<exo::WMHelperChromeOS>(Shell::Get()->aura_env());
     exo::WMHelper::SetInstance(wm_helper_.get());
   }
 
diff --git a/ash/keyboard/ash_keyboard_controller.cc b/ash/keyboard/ash_keyboard_controller.cc
index 48c5573..c81bf0e 100644
--- a/ash/keyboard/ash_keyboard_controller.cc
+++ b/ash/keyboard/ash_keyboard_controller.cc
@@ -113,7 +113,11 @@
   UpdateEnableFlag(was_enabled);
 }
 
-void AshKeyboardController::ReloadKeyboard() {
+void AshKeyboardController::ReloadKeyboardIfNeeded() {
+  keyboard_controller_->Reload();
+}
+
+void AshKeyboardController::RebuildKeyboardIfEnabled() {
   // Test IsKeyboardEnableRequested in case of an unlikely edge case where this
   // is called while after the enable state changed to disabled (in which case
   // we do not want to override the requested state).
@@ -121,6 +125,29 @@
     EnableKeyboard();
 }
 
+void AshKeyboardController::IsKeyboardVisible(
+    IsKeyboardVisibleCallback callback) {
+  std::move(callback).Run(keyboard_controller_->IsKeyboardVisible());
+}
+
+void AshKeyboardController::ShowKeyboard() {
+  if (keyboard_controller_->IsEnabled())
+    keyboard_controller_->ShowKeyboard(false /* lock */);
+}
+
+void AshKeyboardController::HideKeyboard(mojom::HideReason reason) {
+  if (!keyboard_controller_->IsEnabled())
+    return;
+  switch (reason) {
+    case mojom::HideReason::kUser:
+      keyboard_controller_->HideKeyboardByUser();
+      break;
+    case mojom::HideReason::kSystem:
+      keyboard_controller_->HideKeyboardExplicitlyBySystem();
+      break;
+  }
+}
+
 void AshKeyboardController::OnSessionStateChanged(
     session_manager::SessionState state) {
   if (!keyboard_controller_->IsKeyboardEnableRequested())
diff --git a/ash/keyboard/ash_keyboard_controller.h b/ash/keyboard/ash_keyboard_controller.h
index 80cc70a..9ec8234 100644
--- a/ash/keyboard/ash_keyboard_controller.h
+++ b/ash/keyboard/ash_keyboard_controller.h
@@ -64,7 +64,11 @@
   void IsKeyboardEnabled(IsKeyboardEnabledCallback callback) override;
   void SetEnableFlag(keyboard::mojom::KeyboardEnableFlag flag) override;
   void ClearEnableFlag(keyboard::mojom::KeyboardEnableFlag flag) override;
-  void ReloadKeyboard() override;
+  void ReloadKeyboardIfNeeded() override;
+  void RebuildKeyboardIfEnabled() override;
+  void IsKeyboardVisible(IsKeyboardVisibleCallback callback) override;
+  void ShowKeyboard() override;
+  void HideKeyboard(mojom::HideReason reason) override;
   void AddObserver(
       mojom::KeyboardControllerObserverAssociatedPtrInfo observer) override;
 
diff --git a/ash/keyboard/ash_keyboard_controller_unittest.cc b/ash/keyboard/ash_keyboard_controller_unittest.cc
index 2421fa5..59f22fe 100644
--- a/ash/keyboard/ash_keyboard_controller_unittest.cc
+++ b/ash/keyboard/ash_keyboard_controller_unittest.cc
@@ -13,6 +13,7 @@
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/window.h"
 #include "ui/keyboard/keyboard_controller.h"
 
 using keyboard::mojom::KeyboardConfig;
@@ -63,7 +64,7 @@
 
   ~TestClient() = default;
 
-  bool GetIsEnabled() {
+  bool IsKeyboardEnabled() {
     keyboard_controller_->IsKeyboardEnabled(base::BindOnce(
         &TestClient::OnIsKeyboardEnabled, base::Unretained(this)));
     keyboard_controller_.FlushForTesting();
@@ -91,19 +92,38 @@
     keyboard_controller_.FlushForTesting();
   }
 
-  void ReloadKeyboard() {
-    keyboard_controller_->ReloadKeyboard();
+  void RebuildKeyboardIfEnabled() {
+    keyboard_controller_->RebuildKeyboardIfEnabled();
+    keyboard_controller_.FlushForTesting();
+  }
+
+  bool IsKeyboardVisible() {
+    keyboard_controller_->IsKeyboardVisible(base::BindOnce(
+        &TestClient::OnIsKeyboardVisible, base::Unretained(this)));
+    keyboard_controller_.FlushForTesting();
+    return is_visible_;
+  }
+
+  void ShowKeyboard() {
+    keyboard_controller_->ShowKeyboard();
+    keyboard_controller_.FlushForTesting();
+  }
+
+  void HideKeyboard() {
+    keyboard_controller_->HideKeyboard(ash::mojom::HideReason::kUser);
     keyboard_controller_.FlushForTesting();
   }
 
   TestObserver* test_observer() const { return test_observer_.get(); }
 
   bool is_enabled_ = false;
+  bool is_visible_ = false;
   int got_keyboard_config_count_ = 0;
   KeyboardConfig keyboard_config_;
 
  private:
   void OnIsKeyboardEnabled(bool enabled) { is_enabled_ = enabled; }
+  void OnIsKeyboardVisible(bool visible) { is_visible_ = visible; }
 
   void OnGetKeyboardConfig(KeyboardConfigPtr config) {
     ++got_keyboard_config_count_;
@@ -196,21 +216,21 @@
 }
 
 TEST_F(AshKeyboardControllerTest, Enabled) {
-  EXPECT_FALSE(test_client()->GetIsEnabled());
+  EXPECT_FALSE(test_client()->IsKeyboardEnabled());
   // Enable the keyboard.
   test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
-  EXPECT_TRUE(test_client()->GetIsEnabled());
+  EXPECT_TRUE(test_client()->IsKeyboardEnabled());
 
   // Set the enable override to disable the keyboard.
   test_client()->SetEnableFlag(KeyboardEnableFlag::kPolicyDisabled);
-  EXPECT_FALSE(test_client()->GetIsEnabled());
+  EXPECT_FALSE(test_client()->IsKeyboardEnabled());
 
   // Clear the enable override; should enable the keyboard.
   test_client()->ClearEnableFlag(KeyboardEnableFlag::kPolicyDisabled);
-  EXPECT_TRUE(test_client()->GetIsEnabled());
+  EXPECT_TRUE(test_client()->IsKeyboardEnabled());
 }
 
-TEST_F(AshKeyboardControllerTest, ReloadKeyboard) {
+TEST_F(AshKeyboardControllerTest, RebuildKeyboardIfEnabled) {
   EXPECT_EQ(0, test_client()->test_observer()->destroyed_count_);
 
   // Enable the keyboard.
@@ -221,8 +241,8 @@
   test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
   EXPECT_EQ(0, test_client()->test_observer()->destroyed_count_);
 
-  // Reload the keyboard. This should destroy the previous keyboard window.
-  test_client()->ReloadKeyboard();
+  // Rebuild the keyboard. This should destroy the previous keyboard window.
+  test_client()->RebuildKeyboardIfEnabled();
   EXPECT_EQ(1, test_client()->test_observer()->destroyed_count_);
 
   // Disable the keyboard. The keyboard window should be destroyed.
@@ -230,4 +250,23 @@
   EXPECT_EQ(2, test_client()->test_observer()->destroyed_count_);
 }
 
+TEST_F(AshKeyboardControllerTest, ShowAndHideKeyboard) {
+  // Enable the keyboard. This will create the keyboard window but not show it.
+  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(keyboard_controller()->GetKeyboardWindow());
+  EXPECT_FALSE(keyboard_controller()->GetKeyboardWindow()->IsVisible());
+
+  test_client()->ShowKeyboard();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(keyboard_controller()->GetKeyboardWindow()->IsVisible());
+
+  test_client()->HideKeyboard();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(keyboard_controller()->GetKeyboardWindow()->IsVisible());
+
+  // TODO(stevenjb): Also use TestObserver and IsKeyboardVisible to test
+  // visibility changes. https://crbug.com/849995.
+}
+
 }  // namespace ash
diff --git a/ash/keyboard/test_keyboard_ui.cc b/ash/keyboard/test_keyboard_ui.cc
index cbe298e..3a6b6c1 100644
--- a/ash/keyboard/test_keyboard_ui.cc
+++ b/ash/keyboard/test_keyboard_ui.cc
@@ -7,9 +7,11 @@
 #include "ash/shell.h"
 #include "ash/window_factory.h"
 #include "ash/wm/window_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/ime/mock_input_method.h"
+#include "ui/keyboard/test/keyboard_test_util.h"
 
 namespace ash {
 
@@ -22,8 +24,15 @@
   keyboard_window_ = window_factory::NewWindow(&delegate_);
   keyboard_window_->Init(ui::LAYER_NOT_DRAWN);
 
-  // TODO(https://crbug.com/849995): Call |callback| instead of having tests
-  // call |NotifyKeyboardWindowLoaded|.
+  // Set a default size for the keyboard.
+  display::Screen* screen = display::Screen::GetScreen();
+  keyboard_window_->SetBounds(keyboard::KeyboardBoundsFromRootBounds(
+      screen->GetPrimaryDisplay().bounds()));
+
+  // Simulate an asynchronous load.
+  base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                   std::move(callback));
+
   return keyboard_window_.get();
 }
 
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc
index 2a97491..edc26ef 100644
--- a/ash/keyboard/virtual_keyboard_controller_unittest.cc
+++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -15,7 +15,7 @@
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/virtual_keyboard/virtual_keyboard_observer.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/wm/tablet_mode/scoped_disable_internal_mouse_and_keyboard.h"
+#include "ash/wm/tablet_mode/internal_input_devices_event_blocker.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
 #include "base/command_line.h"
@@ -89,7 +89,7 @@
 
 // Mock event blocker that enables the internal keyboard when it's destructor
 // is called.
-class MockEventBlocker : public ScopedDisableInternalMouseAndKeyboard {
+class MockEventBlocker : public InternalInputDevicesEventBlocker {
  public:
   MockEventBlocker() = default;
   ~MockEventBlocker() override {
@@ -108,7 +108,7 @@
 TEST_F(VirtualKeyboardControllerTest, RestoreKeyboardDevices) {
   // Toggle tablet mode on.
   Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-  std::unique_ptr<ScopedDisableInternalMouseAndKeyboard> blocker(
+  std::unique_ptr<InternalInputDevicesEventBlocker> blocker(
       new MockEventBlocker);
   TabletModeControllerTestApi().set_event_blocker(std::move(blocker));
 }
@@ -589,8 +589,8 @@
 
   // Load in the primary display.
   keyboard_controller_->LoadKeyboardWindowInBackground();
-  keyboard_controller_->GetKeyboardWindow()->SetBounds(gfx::Rect(0, 0, 10, 10));
-  keyboard_controller_->NotifyKeyboardWindowLoaded();
+  // Wait for the keyboard window to load.
+  base::RunLoop().RunUntilIdle();
 
   // Show in secondary display.
   keyboard_controller_->ShowKeyboardInDisplay(GetSecondaryDisplay());
diff --git a/ash/keyboard/virtual_keyboard_unittest.cc b/ash/keyboard/virtual_keyboard_unittest.cc
index 2f4a73d..9970e31 100644
--- a/ash/keyboard/virtual_keyboard_unittest.cc
+++ b/ash/keyboard/virtual_keyboard_unittest.cc
@@ -10,6 +10,7 @@
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_switches.h"
 #include "ui/keyboard/keyboard_util.h"
+#include "ui/keyboard/test/keyboard_test_util.h"
 
 namespace ash {
 
@@ -45,10 +46,7 @@
 
   auto* keyboard_controller = keyboard::KeyboardController::Get();
   keyboard_controller->ShowKeyboard(false);
-  keyboard_controller->NotifyKeyboardWindowLoaded();
-
-  aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
-  keyboard_window->SetBounds(gfx::Rect(100, 100, 100, 100));
+  ASSERT_TRUE(keyboard::WaitUntilShown());
 
   // Add two hit test bounds (coordinates relative to keyboard window).
   // Both are 10x10 squares, but placed in different locations.
@@ -60,7 +58,8 @@
   // Click at various places within the keyboard window and check whether the
   // event passes through the keyboard window to the background window.
   ui::test::EventGenerator generator(root_window);
-  const gfx::Point origin = keyboard_window->bounds().origin();
+  const gfx::Point origin =
+      keyboard_controller->visual_bounds_in_screen().origin();
 
   // (0, 0) is inside the first hit rect, so the event is handled by the window
   // and is not received by the background window.
@@ -97,15 +96,13 @@
 
   auto* keyboard_controller = keyboard::KeyboardController::Get();
   keyboard_controller->ShowKeyboard(false);
-  keyboard_controller->NotifyKeyboardWindowLoaded();
-
-  aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
-  keyboard_window->SetBounds(gfx::Rect(100, 100, 100, 100));
+  ASSERT_TRUE(keyboard::WaitUntilShown());
 
   // Set empty hit test bounds, so all events pass through to the background.
   keyboard_controller->SetHitTestBounds(std::vector<gfx::Rect>());
 
   ui::test::EventGenerator generator(root_window);
+  aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
 
   // (0, 0) passes through and is received by background window.
   generator.MoveMouseTo(keyboard_window->bounds().origin());
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index 3a08e49..ab10dec 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -25,7 +25,6 @@
 #include "base/debug/alias.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chromeos/cryptohome/system_salt_getter.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/session_manager/session_manager_types.h"
 
@@ -122,13 +121,15 @@
       return;
   }
 
-  // |DoAuthenticateUser| requires the system salt.
-  authentication_stage_ = AuthenticationStage::kGetSystemSalt;
-  chromeos::SystemSaltGetter::Get()->GetSystemSalt(
-      base::AdaptCallbackForRepeating(
-          base::BindOnce(&LoginScreenController::DoAuthenticateUser,
-                         weak_factory_.GetWeakPtr(), account_id, password,
-                         authenticated_by_pin, std::move(callback))));
+  authentication_stage_ = AuthenticationStage::kDoAuthenticate;
+
+  int dummy_value;
+  bool is_pin =
+      authenticated_by_pin && base::StringToInt(password, &dummy_value);
+  login_screen_client_->AuthenticateUserWithPasswordOrPin(
+      account_id, password, is_pin,
+      base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
+                     weak_factory_.GetWeakPtr(), base::Passed(&callback)));
 }
 
 void LoginScreenController::AuthenticateUserWithExternalBinary(
@@ -494,7 +495,9 @@
   Shelf* shelf = Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow());
   // Tell the focus direction to the status area or the shelf so they can focus
   // the correct child view.
-  if (reverse) {
+  if (reverse && !ShelfWidget::IsUsingViewsShelf()) {
+    if (Shell::GetPrimaryRootWindowController()->IsSystemTrayVisible())
+      return;
     shelf->GetStatusAreaWidget()
         ->status_area_widget_delegate()
         ->set_default_last_focusable_child(reverse);
@@ -532,24 +535,6 @@
   login_screen_client_->FocusOobeDialog();
 }
 
-void LoginScreenController::DoAuthenticateUser(const AccountId& account_id,
-                                               const std::string& password,
-                                               bool authenticated_by_pin,
-                                               OnAuthenticateCallback callback,
-                                               const std::string& system_salt) {
-  // TODO(jdufault): Simplify this, system_salt is no longer used so fetching
-  // the system salt can be skipped.
-  authentication_stage_ = AuthenticationStage::kDoAuthenticate;
-
-  int dummy_value;
-  bool is_pin =
-      authenticated_by_pin && base::StringToInt(password, &dummy_value);
-  login_screen_client_->AuthenticateUserWithPasswordOrPin(
-      account_id, password, is_pin,
-      base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
-                     weak_factory_.GetWeakPtr(), base::Passed(&callback)));
-}
-
 void LoginScreenController::OnAuthenticateComplete(
     OnAuthenticateCallback callback,
     bool success) {
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h
index 738741e..78d1771 100644
--- a/ash/login/login_screen_controller.h
+++ b/ash/login/login_screen_controller.h
@@ -30,7 +30,6 @@
   // The current authentication stage. Used to get more verbose logging.
   enum class AuthenticationStage {
     kIdle,
-    kGetSystemSalt,
     kDoAuthenticate,
     kUserCallback,
   };
@@ -162,14 +161,6 @@
   }
 
  private:
-  using PendingDoAuthenticateUser =
-      base::OnceCallback<void(const std::string& system_salt)>;
-
-  void DoAuthenticateUser(const AccountId& account_id,
-                          const std::string& password,
-                          bool authenticated_by_pin,
-                          OnAuthenticateCallback callback,
-                          const std::string& system_salt);
   void OnAuthenticateComplete(OnAuthenticateCallback callback, bool success);
 
   // Returns the active data dispatcher or nullptr if there is no lock screen.
diff --git a/ash/login/login_screen_controller_unittest.cc b/ash/login/login_screen_controller_unittest.cc
index 7c73d94..43d4884 100644
--- a/ash/login/login_screen_controller_unittest.cc
+++ b/ash/login/login_screen_controller_unittest.cc
@@ -12,7 +12,6 @@
 #include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wallpaper/wallpaper_controller.h"
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 43f7a56..23471be 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -418,6 +418,9 @@
 }
 
 void LockContentsView::FocusNextUser() {
+  if (users_.empty())
+    return;
+
   if (login_views_utils::HasFocusInAnyChildView(primary_big_view_)) {
     if (opt_secondary_big_view_) {
       SwapActiveAuthBetweenPrimaryAndSecondary(false /*is_primary*/);
@@ -454,6 +457,9 @@
 }
 
 void LockContentsView::FocusPreviousUser() {
+  if (users_.empty())
+    return;
+
   if (login_views_utils::HasFocusInAnyChildView(primary_big_view_)) {
     if (users_list_) {
       users_list_->user_view_at(users_list_->user_count() - 1)->RequestFocus();
@@ -1041,25 +1047,12 @@
   }
 }
 
-void LockContentsView::OnStateChanged(
-    const keyboard::KeyboardControllerState state) {
-  if (!primary_big_view_)
+void LockContentsView::OnKeyboardVisibilityStateChanged(bool is_visible) {
+  if (!primary_big_view_ || keyboard_shown_ == is_visible)
     return;
 
-  if (state == keyboard::KeyboardControllerState::SHOWN ||
-      state == keyboard::KeyboardControllerState::HIDDEN) {
-    bool keyboard_will_be_shown =
-        state == keyboard::KeyboardControllerState::SHOWN;
-    // Keyboard state can go from SHOWN -> SomeStateOtherThanShownOrHidden ->
-    // SHOWN when we click on the inactive BigUser while the virtual keyboard is
-    // active. In this case, we should do nothing, since
-    // SwapActiveAuthBetweenPrimaryAndSecondary handles the re-layout.
-    if (keyboard_shown_ == keyboard_will_be_shown)
-      return;
-    keyboard_shown_ = keyboard_will_be_shown;
-    LayoutAuth(CurrentBigUserView(), nullptr /*opt_to_hide*/,
-               false /*animate*/);
-  }
+  keyboard_shown_ = is_visible;
+  LayoutAuth(CurrentBigUserView(), nullptr /*opt_to_hide*/, false /*animate*/);
 }
 
 void LockContentsView::SuspendImminent(
@@ -1345,12 +1338,13 @@
         to_update_auth = LoginAuthUserView::AUTH_DISABLED;
       } else {
         to_update_auth = LoginAuthUserView::AUTH_PASSWORD;
-        keyboard::KeyboardController* keyboard_controller =
-            GetKeyboardController();
-        const bool is_keyboard_visible =
-            keyboard_controller ? keyboard_controller->IsKeyboardVisible()
-                                : false;
-        if (state->show_pin && !is_keyboard_visible)
+        // Need to check |GetKeyboardControllerForView| as the keyboard may be
+        // visible, but the keyboard is in a different root window or the view
+        // has not been added to the widget. In these cases, the keyboard does
+        // not interfere with PIN entry.
+        const bool is_keyboard_visible_for_view =
+            GetKeyboardControllerForView() ? keyboard_shown_ : false;
+        if (state->show_pin && !is_keyboard_visible_for_view)
           to_update_auth |= LoginAuthUserView::AUTH_PIN;
         if (state->enable_tap_auth)
           to_update_auth |= LoginAuthUserView::AUTH_TAP;
@@ -1611,7 +1605,8 @@
   }
 }
 
-keyboard::KeyboardController* LockContentsView::GetKeyboardController() const {
+keyboard::KeyboardController* LockContentsView::GetKeyboardControllerForView()
+    const {
   return GetWidget() ? GetKeyboardControllerForWidget(GetWidget()) : nullptr;
 }
 
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 8637246..6807ed3 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -193,7 +193,7 @@
   void OnLockStateChanged(bool locked) override;
 
   // keyboard::KeyboardControllerObserver:
-  void OnStateChanged(const keyboard::KeyboardControllerState state) override;
+  void OnKeyboardVisibilityStateChanged(bool is_visible) override;
 
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
@@ -302,7 +302,7 @@
   // Returns keyboard controller for the view. Returns nullptr if keyboard is
   // not activated, view has not been added to the widget yet or keyboard is not
   // displayed in this window.
-  keyboard::KeyboardController* GetKeyboardController() const;
+  keyboard::KeyboardController* GetKeyboardControllerForView() const;
 
   // Called when the public account is tapped.
   void OnPublicAccountTapped(bool is_primary);
@@ -397,9 +397,8 @@
   // Expanded view for public account user to select language and keyboard.
   LoginExpandedPublicAccountView* expanded_view_ = nullptr;
 
-  // Whether the virtual keyboard is currently shown. Only changes when the
-  // keyboard state changes to KeyboardControllerState::SHOWN or to
-  // KeyboardControllerState::HIDDEN.
+  // Whether the virtual keyboard is currently shown. Used to determine whether
+  // to show the PIN keyboard or not.
   bool keyboard_shown_ = false;
 
   // Accelerators handled by login screen.
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc
index 8df9d71..d35d155 100644
--- a/ash/login/ui/lock_contents_view_unittest.cc
+++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -2138,4 +2138,17 @@
   Shell::Get()->power_button_controller()->OnTabletModeEnded();
 }
 
+TEST_F(LockContentsViewUnitTest, RightAndLeftAcceleratorsWithNoUser) {
+  // Show lock screen but do *not* initialize any users.
+  auto* lock = new LockContentsView(
+      mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLock,
+      data_dispatcher(),
+      std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher()));
+  SetWidget(CreateWidgetWithContent(lock));
+
+  // Nothing to validate except that there is no crash.
+  lock->AcceleratorPressed(ui::Accelerator(ui::VKEY_RIGHT, 0));
+  lock->AcceleratorPressed(ui::Accelerator(ui::VKEY_LEFT, 0));
+}
+
 }  // namespace ash
diff --git a/ash/login/ui/login_keyboard_test_base.cc b/ash/login/ui/login_keyboard_test_base.cc
index d6786ba..7d8c7fe 100644
--- a/ash/login/ui/login_keyboard_test_base.cc
+++ b/ash/login/ui/login_keyboard_test_base.cc
@@ -49,14 +49,11 @@
   keyboard_controller->ShowKeyboard(false);
   // Set keyboard height to half of the root window - this should overlap with
   // lock/login layout.
-  if (keyboard_controller->GetKeyboardWindow()->bounds().height() == 0) {
-    int height = Shell::GetPrimaryRootWindow()->bounds().height() / 2;
-    keyboard_controller->GetKeyboardWindow()->SetBounds(
-        keyboard::KeyboardBoundsFromRootBounds(
-            Shell::GetPrimaryRootWindow()->bounds(), height));
-    keyboard_controller->NotifyKeyboardWindowLoaded();
-  }
-  ASSERT_TRUE(keyboard_controller->IsKeyboardVisible());
+  int height = Shell::GetPrimaryRootWindow()->bounds().height() / 2;
+  keyboard_controller->GetKeyboardWindow()->SetBounds(
+      keyboard::KeyboardBoundsFromRootBounds(
+          Shell::GetPrimaryRootWindow()->bounds(), height));
+  ASSERT_TRUE(keyboard::WaitUntilShown());
 }
 
 void LoginKeyboardTestBase::HideKeyboard() {
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc
index 0d14127..bd3b53a 100644
--- a/ash/login/ui/login_password_view.cc
+++ b/ash/login/ui/login_password_view.cc
@@ -13,7 +13,6 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
-#include "ash/system/user/button_from_view.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_node_data.h"
diff --git a/ash/magnifier/magnification_controller_unittest.cc b/ash/magnifier/magnification_controller_unittest.cc
index a867b6e..ce46ad0 100644
--- a/ash/magnifier/magnification_controller_unittest.cc
+++ b/ash/magnifier/magnification_controller_unittest.cc
@@ -982,9 +982,6 @@
   auto* keyboard_controller = keyboard::KeyboardController::Get();
   keyboard_controller->ShowKeyboard(true);
 
-  gfx::Rect keyboard_bounds = gfx::Rect(0, 300, 800, 300);
-  keyboard_controller->GetKeyboardWindow()->SetBounds(keyboard_bounds);
-
   // Focus on the text input field.
   text_input_helper_.FocusOnTextInputView();
   base::RunLoop().RunUntilIdle();
@@ -993,7 +990,8 @@
   gfx::Rect viewport_outside_keyboard_bounds = GetViewport();
   viewport_outside_keyboard_bounds.set_height(
       viewport_outside_keyboard_bounds.height() -
-      keyboard_bounds.height() / GetMagnificationController()->GetScale());
+      keyboard_controller->visual_bounds_in_screen().height() /
+          GetMagnificationController()->GetScale());
 
   gfx::Rect caret_bounds = text_input_helper_.GetCaretBounds();
 
diff --git a/ash/media/media_notification_controller.cc b/ash/media/media_notification_controller.cc
index 1508534..c65181a 100644
--- a/ash/media/media_notification_controller.cc
+++ b/ash/media/media_notification_controller.cc
@@ -6,8 +6,10 @@
 
 #include "ash/media/media_notification_constants.h"
 #include "ash/media/media_notification_view.h"
+#include "ash/public/cpp/notification_utils.h"
 #include "base/strings/string16.h"
 #include "services/media_session/public/mojom/constants.mojom.h"
+#include "services/media_session/public/mojom/media_controller.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/gfx/image/image.h"
 #include "ui/message_center/public/cpp/notification.h"
@@ -50,27 +52,36 @@
   media_session::mojom::AudioFocusManagerPtr audio_focus_ptr;
   connector->BindInterface(media_session::mojom::kServiceName,
                            mojo::MakeRequest(&audio_focus_ptr));
+  connector->BindInterface(media_session::mojom::kServiceName,
+                           mojo::MakeRequest(&media_controller_ptr_));
 
-  media_session::mojom::AudioFocusObserverPtr observer;
-  binding_.Bind(mojo::MakeRequest(&observer));
-  audio_focus_ptr->AddObserver(std::move(observer));
+  media_session::mojom::AudioFocusObserverPtr audio_focus_observer;
+  audio_focus_observer_binding_.Bind(mojo::MakeRequest(&audio_focus_observer));
+  audio_focus_ptr->AddObserver(std::move(audio_focus_observer));
+
+  media_session::mojom::MediaSessionObserverPtr media_session_observer;
+  media_session_observer_binding_.Bind(
+      mojo::MakeRequest(&media_session_observer));
+  media_controller_ptr_->AddObserver(std::move(media_session_observer));
 }
 
 MediaNotificationController::~MediaNotificationController() = default;
 
 void MediaNotificationController::OnFocusGained(
-    media_session::mojom::MediaSessionInfoPtr media_session,
+    media_session::mojom::MediaSessionInfoPtr session_info,
     media_session::mojom::AudioFocusType type) {
   if (IsMediaSessionNotificationVisible())
     return;
 
+  session_info_ = std::move(session_info);
+
   std::unique_ptr<message_center::Notification> notification =
-      message_center::Notification::CreateSystemNotification(
+      ash::CreateSystemNotification(
           message_center::NotificationType::NOTIFICATION_TYPE_CUSTOM,
           kMediaSessionNotificationId, base::string16(), base::string16(),
           base::string16(), GURL(),
           message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT,
+              message_center::NotifierType::SYSTEM_COMPONENT,
               kMediaSessionNotifierId),
           message_center::RichNotificationData(),
           base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
@@ -91,7 +102,7 @@
 }
 
 void MediaNotificationController::OnFocusLost(
-    media_session::mojom::MediaSessionInfoPtr media_session) {
+    media_session::mojom::MediaSessionInfoPtr session_info) {
   if (!IsMediaSessionNotificationVisible())
     return;
 
@@ -99,9 +110,47 @@
       kMediaSessionNotificationId, false);
 }
 
+void MediaNotificationController::MediaSessionInfoChanged(
+    media_session::mojom::MediaSessionInfoPtr session_info) {
+  session_info_ = std::move(session_info);
+
+  if (view_)
+    view_->UpdateWithMediaSessionInfo(session_info_);
+}
+
+void MediaNotificationController::FlushForTesting() {
+  media_controller_ptr_.FlushForTesting();
+}
+
+void MediaNotificationController::SetView(MediaNotificationView* view) {
+  DCHECK(view_ || view);
+
+  view_ = view;
+
+  if (view) {
+    DCHECK(!session_info_.is_null());
+    view_->UpdateWithMediaSessionInfo(session_info_);
+  }
+}
+
 void MediaNotificationController::OnNotificationClicked(
     base::Optional<int> button_id) {
-  NOTIMPLEMENTED();
+  DCHECK(button_id.has_value());
+
+  // TODO(beccahughes): Replace with MediaSessionAction enum when moved.
+  switch (*button_id) {
+    case 0:
+      media_controller_ptr_->PreviousTrack();
+      break;
+    case 1:
+      media_controller_ptr_->ToggleSuspendResume();
+      break;
+    case 2:
+      media_controller_ptr_->NextTrack();
+      break;
+    default:
+      NOTREACHED();
+  }
 }
 
 }  // namespace ash
diff --git a/ash/media/media_notification_controller.h b/ash/media/media_notification_controller.h
index 8b4cff4..130bd23 100644
--- a/ash/media/media_notification_controller.h
+++ b/ash/media/media_notification_controller.h
@@ -11,6 +11,7 @@
 #include "base/optional.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/media_session/public/mojom/audio_focus.mojom.h"
+#include "services/media_session/public/mojom/media_controller.mojom.h"
 #include "ui/message_center/message_center.h"
 
 namespace service_manager {
@@ -19,25 +20,51 @@
 
 namespace ash {
 
+class MediaNotificationView;
+
 // MediaNotificationController will show/hide a media notification when a media
 // session is active. This notification will show metadata and playback
 // controls.
 class ASH_EXPORT MediaNotificationController
-    : public media_session::mojom::AudioFocusObserver {
+    : public media_session::mojom::AudioFocusObserver,
+      public media_session::mojom::MediaSessionObserver {
  public:
   explicit MediaNotificationController(service_manager::Connector* connector);
   ~MediaNotificationController() override;
 
-  // AudioFocusObserver implementation.
-  void OnFocusGained(media_session::mojom::MediaSessionInfoPtr media_session,
+  // media_session::mojom::AudioFocusObserver:
+  void OnFocusGained(media_session::mojom::MediaSessionInfoPtr session_info,
                      media_session::mojom::AudioFocusType type) override;
   void OnFocusLost(
-      media_session::mojom::MediaSessionInfoPtr media_session) override;
+      media_session::mojom::MediaSessionInfoPtr session_info) override;
+
+  // media_session::mojom::MediaSessionObserver:
+  void MediaSessionInfoChanged(
+      media_session::mojom::MediaSessionInfoPtr session_info) override;
+
+  void FlushForTesting();
+  void SetMediaControllerForTesting(
+      media_session::mojom::MediaControllerPtr controller) {
+    media_controller_ptr_ = std::move(controller);
+  }
+
+  void SetView(MediaNotificationView* view);
 
  private:
+  // Weak reference to the view of the currently shown media notification.
+  MediaNotificationView* view_ = nullptr;
+
   void OnNotificationClicked(base::Optional<int> button_id);
 
-  mojo::Binding<media_session::mojom::AudioFocusObserver> binding_{this};
+  media_session::mojom::MediaControllerPtr media_controller_ptr_;
+
+  media_session::mojom::MediaSessionInfoPtr session_info_;
+
+  mojo::Binding<media_session::mojom::AudioFocusObserver>
+      audio_focus_observer_binding_{this};
+
+  mojo::Binding<media_session::mojom::MediaSessionObserver>
+      media_session_observer_binding_{this};
 
   base::WeakPtrFactory<MediaNotificationController> weak_ptr_factory_{this};
 
diff --git a/ash/media/media_notification_view.cc b/ash/media/media_notification_view.cc
index 4c62894..98ea57c 100644
--- a/ash/media/media_notification_view.cc
+++ b/ash/media/media_notification_view.cc
@@ -4,14 +4,33 @@
 
 #include "ash/media/media_notification_view.h"
 
+#include "ash/media/media_notification_constants.h"
+#include "ash/media/media_notification_controller.h"
+#include "ash/shell.h"
+#include "components/vector_icons/vector_icons.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/message_center/views/notification_control_buttons_view.h"
 #include "ui/message_center/views/notification_header_view.h"
+#include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/style/typography.h"
 
 namespace ash {
 
+namespace {
+
+// Dimensions.
+constexpr gfx::Insets kButtonRowPadding(0, 12, 16, 12);
+constexpr int kMediaButtonIconSize = 32;
+
+SkColor GetMediaNotificationColor(const views::View& view) {
+  return views::style::GetColor(view, views::style::CONTEXT_LABEL,
+                                views::style::STYLE_PRIMARY);
+}
+
+}  // namespace
+
 MediaNotificationView::MediaNotificationView(
     const message_center::Notification& notification)
     : message_center::MessageView(notification) {
@@ -23,7 +42,7 @@
       std::make_unique<message_center::NotificationControlButtonsView>(this);
   control_buttons_view_->set_owned_by_client();
 
-  // |header_row_| contains app_icon, app_name, control buttons, etc...
+  // |header_row_| contains app_icon, app_name, control buttons, etc.
   header_row_ = new message_center::NotificationHeaderView(
       control_buttons_view_.get(), this);
   header_row_->SetExpandButtonEnabled(false);
@@ -31,14 +50,44 @@
       message_center::MessageCenter::Get()->GetSystemNotificationAppName());
   AddChildView(header_row_);
 
+  // |button_row_| contains the buttons for controlling playback.
+  button_row_ = new views::View();
+  auto* button_row_layout =
+      button_row_->SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::kHorizontal, kButtonRowPadding, 16));
+  button_row_layout->set_main_axis_alignment(
+      views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
+  button_row_layout->set_cross_axis_alignment(
+      views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
+  AddChildView(button_row_);
+
+  CreateMediaButton(vector_icons::kMediaPreviousTrackIcon);
+
+  // |play_pause_button_| toggles playback.
+  play_pause_button_ = views::CreateVectorToggleImageButton(this);
+  SkColor play_button_color = GetMediaNotificationColor(*play_pause_button_);
+  views::SetImageFromVectorIcon(play_pause_button_,
+                                vector_icons::kPlayArrowIcon,
+                                kMediaButtonIconSize, play_button_color);
+  views::SetToggledImageFromVectorIcon(play_pause_button_,
+                                       vector_icons::kPauseIcon,
+                                       kMediaButtonIconSize, play_button_color);
+  button_row_->AddChildView(play_pause_button_);
+
+  CreateMediaButton(vector_icons::kMediaNextTrackIcon);
+
   // TODO(beccahughes): Add remaining UI for notification.
 
   UpdateControlButtonsVisibilityWithNotification(notification);
   UpdateCornerRadius(message_center::kNotificationCornerRadius,
                      message_center::kNotificationCornerRadius);
+
+  Shell::Get()->media_notification_controller()->SetView(this);
 }
 
-MediaNotificationView::~MediaNotificationView() = default;
+MediaNotificationView::~MediaNotificationView() {
+  Shell::Get()->media_notification_controller()->SetView(nullptr);
+}
 
 void MediaNotificationView::UpdateWithNotification(
     const message_center::Notification& notification) {
@@ -78,7 +127,17 @@
 
 void MediaNotificationView::ButtonPressed(views::Button* sender,
                                           const ui::Event& event) {
-  NOTIMPLEMENTED();
+  if (sender->parent() == button_row_) {
+    message_center::MessageCenter::Get()->ClickOnNotificationButton(
+        notification_id(), sender->parent()->GetIndexOf(sender));
+  }
+}
+
+void MediaNotificationView::UpdateWithMediaSessionInfo(
+    const media_session::mojom::MediaSessionInfoPtr& session_info) {
+  play_pause_button_->SetToggled(
+      session_info->playback_state ==
+      media_session::mojom::MediaPlaybackState::kPlaying);
 }
 
 void MediaNotificationView::UpdateControlButtonsVisibilityWithNotification(
@@ -91,4 +150,11 @@
   UpdateControlButtonsVisibility();
 }
 
+void MediaNotificationView::CreateMediaButton(const gfx::VectorIcon& icon) {
+  views::ImageButton* button = views::CreateVectorImageButton(this);
+  views::SetImageFromVectorIcon(button, icon, kMediaButtonIconSize,
+                                GetMediaNotificationColor(*button));
+  button_row_->AddChildView(button);
+}
+
 }  // namespace ash
diff --git a/ash/media/media_notification_view.h b/ash/media/media_notification_view.h
index fe1d6cf3..6cdc6af 100644
--- a/ash/media/media_notification_view.h
+++ b/ash/media/media_notification_view.h
@@ -6,13 +6,20 @@
 #define ASH_MEDIA_MEDIA_NOTIFICATION_VIEW_H_
 
 #include "ash/ash_export.h"
+#include "services/media_session/public/mojom/media_session.mojom.h"
 #include "ui/message_center/views/message_view.h"
 #include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/image_button.h"
 
 namespace message_center {
 class NotificationHeaderView;
 }  // namespace message_center
 
+namespace views {
+class ToggleImageButton;
+class View;
+}  // namespace views
+
 namespace ash {
 
 // MediaNotificationView will show up as a custom notification. It will show the
@@ -39,16 +46,26 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
+  void UpdateWithMediaSessionInfo(
+      const media_session::mojom::MediaSessionInfoPtr& session_info);
+
  private:
+  friend class MediaNotificationViewTest;
+
   void UpdateControlButtonsVisibilityWithNotification(
       const message_center::Notification& notification);
 
+  // Creates an image button with |icon| and adds it to |button_row_|.
+  void CreateMediaButton(const gfx::VectorIcon& icon);
+
   // View containing close and settings buttons.
   std::unique_ptr<message_center::NotificationControlButtonsView>
       control_buttons_view_;
 
   // Container views directly attached to this view.
   message_center::NotificationHeaderView* header_row_ = nullptr;
+  views::View* button_row_ = nullptr;
+  views::ToggleImageButton* play_pause_button_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(MediaNotificationView);
 };
diff --git a/ash/media/media_notification_view_unittest.cc b/ash/media/media_notification_view_unittest.cc
index 2c1e16a..ff521b2 100644
--- a/ash/media/media_notification_view_unittest.cc
+++ b/ash/media/media_notification_view_unittest.cc
@@ -17,6 +17,7 @@
 #include "ash/test/ash_test_base.h"
 #include "base/macros.h"
 #include "base/test/scoped_feature_list.h"
+#include "services/media_session/public/cpp/test/test_media_controller.h"
 #include "services/media_session/public/mojom/audio_focus.mojom.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/test/event_generator.h"
@@ -26,6 +27,22 @@
 
 namespace ash {
 
+using media_session::test::TestMediaController;
+
+namespace {
+
+// The icons size is 32 and INSETS_VECTOR_IMAGE_BUTTON will add padding around
+// the image.
+const int kMediaButtonIconSize = 40;
+
+// Checks if the view class name is used by a media button.
+bool IsMediaButtonType(const char* class_name) {
+  return class_name == views::ImageButton::kViewClassName ||
+         class_name == views::ToggleImageButton::kViewClassName;
+}
+
+}  // namespace
+
 class MediaNotificationViewTest : public AshTestBase {
  public:
   MediaNotificationViewTest() = default;
@@ -38,6 +55,18 @@
 
     AshTestBase::SetUp();
 
+    media_controller_ = std::make_unique<TestMediaController>();
+    Shell::Get()->media_notification_controller()->SetMediaControllerForTesting(
+        media_controller_->CreateMediaControllerPtr());
+
+    ShowNotificationAndCaptureView(
+        media_session::mojom::MediaSessionInfo::New());
+  }
+
+  void ShowNotificationAndCaptureView(
+      media_session::mojom::MediaSessionInfoPtr session_info) {
+    view_ = nullptr;
+
     // Set a custom view factory to create and capture the notification view.
     message_center::MessageViewFactory::
         ClearCustomNotificationViewFactoryForTest(
@@ -50,8 +79,7 @@
 
     // Show the notification.
     Shell::Get()->media_notification_controller()->OnFocusGained(
-        media_session::mojom::MediaSessionInfo::New(),
-        media_session::mojom::AudioFocusType::kGain);
+        std::move(session_info), media_session::mojom::AudioFocusType::kGain);
 
     message_center::Notification* notification =
         message_center::MessageCenter::Get()->FindVisibleNotificationById(
@@ -62,6 +90,7 @@
     auto* unified_system_tray =
         StatusAreaWidgetTestHelper::GetStatusAreaWidget()
             ->unified_system_tray();
+    unified_system_tray->SetTrayEnabled(true);
     unified_system_tray->ShowBubble(false /* show_by_click */);
     unified_system_tray->ActivateBubble();
 
@@ -86,6 +115,12 @@
 
   MediaNotificationView* view() const { return view_; }
 
+  TestMediaController* media_controller() const {
+    return media_controller_.get();
+  }
+
+  views::View* button_row() const { return view_->button_row_; }
+
  private:
   std::unique_ptr<message_center::MessageView> CreateAndCaptureCustomView(
       const message_center::Notification& notification) {
@@ -96,6 +131,7 @@
 
   base::test::ScopedFeatureList scoped_feature_list_;
 
+  std::unique_ptr<TestMediaController> media_controller_;
   std::unique_ptr<views::Widget> widget_;
   MediaNotificationView* view_ = nullptr;
 
@@ -124,4 +160,139 @@
   EXPECT_FALSE(IsControlButtonsViewVisible());
 }
 
+TEST_F(MediaNotificationViewTest, ButtonsSanityCheck) {
+  EXPECT_TRUE(button_row()->visible());
+  EXPECT_GT(button_row()->width(), 0);
+  EXPECT_GT(button_row()->height(), 0);
+
+  EXPECT_EQ(3, button_row()->child_count());
+
+  for (int i = 0; i < button_row()->child_count(); ++i) {
+    const views::Button* child =
+        views::Button::AsButton(button_row()->child_at(i));
+    ASSERT_TRUE(IsMediaButtonType(child->GetClassName()));
+
+    EXPECT_TRUE(child->visible());
+    EXPECT_EQ(kMediaButtonIconSize, child->width());
+    EXPECT_EQ(kMediaButtonIconSize, child->height());
+  }
+}
+
+TEST_F(MediaNotificationViewTest, NextTrackButtonClick) {
+  EXPECT_EQ(0, media_controller()->next_track_count());
+
+  gfx::Point cursor_location(1, 1);
+  views::View::ConvertPointToScreen(button_row()->child_at(2),
+                                    &cursor_location);
+  GetEventGenerator()->MoveMouseTo(cursor_location.x(), cursor_location.y());
+  GetEventGenerator()->ClickLeftButton();
+  Shell::Get()->media_notification_controller()->FlushForTesting();
+
+  EXPECT_EQ(1, media_controller()->next_track_count());
+}
+
+TEST_F(MediaNotificationViewTest, PlayPauseButtonClick) {
+  EXPECT_EQ(0, media_controller()->toggle_suspend_resume_count());
+
+  gfx::Point cursor_location(1, 1);
+  views::View::ConvertPointToScreen(button_row()->child_at(1),
+                                    &cursor_location);
+  GetEventGenerator()->MoveMouseTo(cursor_location.x(), cursor_location.y());
+  GetEventGenerator()->ClickLeftButton();
+  Shell::Get()->media_notification_controller()->FlushForTesting();
+
+  EXPECT_EQ(1, media_controller()->toggle_suspend_resume_count());
+}
+
+TEST_F(MediaNotificationViewTest, PreviousTrackButtonClick) {
+  EXPECT_EQ(0, media_controller()->previous_track_count());
+
+  gfx::Point cursor_location(1, 1);
+  views::View::ConvertPointToScreen(button_row()->child_at(0),
+                                    &cursor_location);
+  GetEventGenerator()->MoveMouseTo(cursor_location.x(), cursor_location.y());
+  GetEventGenerator()->ClickLeftButton();
+  Shell::Get()->media_notification_controller()->FlushForTesting();
+
+  EXPECT_EQ(1, media_controller()->previous_track_count());
+}
+
+TEST_F(MediaNotificationViewTest, ClickNotification) {
+  EXPECT_EQ(0, media_controller()->toggle_suspend_resume_count());
+
+  gfx::Point cursor_location(1, 1);
+  views::View::ConvertPointToScreen(view(), &cursor_location);
+  GetEventGenerator()->MoveMouseTo(cursor_location.x(), cursor_location.y());
+  GetEventGenerator()->ClickLeftButton();
+  Shell::Get()->media_notification_controller()->FlushForTesting();
+
+  EXPECT_EQ(0, media_controller()->toggle_suspend_resume_count());
+}
+
+TEST_F(MediaNotificationViewTest, PlayToggle_FromFocusGain) {
+  {
+    views::ToggleImageButton* button =
+        static_cast<views::ToggleImageButton*>(button_row()->child_at(1));
+    ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName());
+    EXPECT_FALSE(button->toggled_for_testing());
+  }
+
+  Shell::Get()->media_notification_controller()->OnFocusLost(
+      media_session::mojom::MediaSessionInfo::New());
+
+  // Disable the tray and run the loop to make sure that the existing view is
+  // destroyed.
+  StatusAreaWidgetTestHelper::GetStatusAreaWidget()
+      ->unified_system_tray()
+      ->SetTrayEnabled(false);
+  base::RunLoop().RunUntilIdle();
+
+  media_session::mojom::MediaSessionInfoPtr session_info(
+      media_session::mojom::MediaSessionInfo::New());
+  session_info->playback_state =
+      media_session::mojom::MediaPlaybackState::kPlaying;
+
+  ShowNotificationAndCaptureView(std::move(session_info));
+
+  {
+    views::ToggleImageButton* button =
+        static_cast<views::ToggleImageButton*>(button_row()->child_at(1));
+    ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName());
+    EXPECT_TRUE(button->toggled_for_testing());
+  }
+}
+
+TEST_F(MediaNotificationViewTest, PlayToggle_FromObserver_Empty) {
+  views::ToggleImageButton* button =
+      static_cast<views::ToggleImageButton*>(button_row()->child_at(1));
+  ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName());
+  EXPECT_FALSE(button->toggled_for_testing());
+
+  Shell::Get()->media_notification_controller()->MediaSessionInfoChanged(
+      media_session::mojom::MediaSessionInfo::New());
+  EXPECT_FALSE(button->toggled_for_testing());
+}
+
+TEST_F(MediaNotificationViewTest, PlayToggle_FromObserver_PlaybackState) {
+  views::ToggleImageButton* button =
+      static_cast<views::ToggleImageButton*>(button_row()->child_at(1));
+  ASSERT_EQ(views::ToggleImageButton::kViewClassName, button->GetClassName());
+  EXPECT_FALSE(button->toggled_for_testing());
+
+  media_session::mojom::MediaSessionInfoPtr session_info(
+      media_session::mojom::MediaSessionInfo::New());
+
+  session_info->playback_state =
+      media_session::mojom::MediaPlaybackState::kPlaying;
+  Shell::Get()->media_notification_controller()->MediaSessionInfoChanged(
+      session_info.Clone());
+  EXPECT_TRUE(button->toggled_for_testing());
+
+  session_info->playback_state =
+      media_session::mojom::MediaPlaybackState::kPaused;
+  Shell::Get()->media_notification_controller()->MediaSessionInfoChanged(
+      session_info.Clone());
+  EXPECT_FALSE(button->toggled_for_testing());
+}
+
 }  // namespace ash
diff --git a/ash/multi_device_setup/multi_device_notification_presenter.cc b/ash/multi_device_setup/multi_device_notification_presenter.cc
index 7e2939d..e142b88 100644
--- a/ash/multi_device_setup/multi_device_notification_presenter.cc
+++ b/ash/multi_device_setup/multi_device_notification_presenter.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/public/cpp/notification_utils.h"
 #include "ash/public/cpp/vector_icons/vector_icons.h"
 #include "ash/public/interfaces/session_controller.mojom.h"
 #include "ash/session/session_controller.h"
@@ -106,6 +107,7 @@
 }
 
 MultiDeviceNotificationPresenter::~MultiDeviceNotificationPresenter() {
+  message_center_->RemoveObserver(this);
   Shell::Get()->session_controller()->RemoveObserver(this);
 }
 
@@ -161,6 +163,48 @@
   ObserveMultiDeviceSetupIfPossible();
 }
 
+void MultiDeviceNotificationPresenter::OnNotificationRemoved(
+    const std::string& notification_id,
+    bool by_user) {
+  if (by_user && notification_id == kNotificationId) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "MultiDeviceSetup_NotificationDismissed",
+        GetMetricValueForNotification(notification_status_),
+        kNotificationTypeMax);
+  }
+}
+
+void MultiDeviceNotificationPresenter::OnNotificationClicked(
+    const std::string& notification_id,
+    const base::Optional<int>& button_index,
+    const base::Optional<base::string16>& reply) {
+  if (notification_id != kNotificationId)
+    return;
+
+  DCHECK(notification_status_ != Status::kNoNotificationVisible);
+  PA_LOG(VERBOSE) << "User clicked "
+                  << GetNotificationDescriptionForLogging(notification_status_)
+                  << ".";
+  UMA_HISTOGRAM_ENUMERATION("MultiDeviceSetup_NotificationClicked",
+                            GetMetricValueForNotification(notification_status_),
+                            kNotificationTypeMax);
+  switch (notification_status_) {
+    case Status::kNewUserNotificationVisible:
+      open_ui_delegate_->OpenMultiDeviceSetupUi();
+      break;
+    case Status::kExistingUserHostSwitchedNotificationVisible:
+      // Clicks on the 'host switched' and 'Chromebook added' notifications have
+      // the same effect, i.e. opening the Settings subpage.
+      FALLTHROUGH;
+    case Status::kExistingUserNewChromebookNotificationVisible:
+      open_ui_delegate_->OpenConnectedDevicesSettings();
+      break;
+    case Status::kNoNotificationVisible:
+      NOTREACHED();
+  }
+  RemoveMultiDeviceSetupNotification();
+}
+
 void MultiDeviceNotificationPresenter::ObserveMultiDeviceSetupIfPossible() {
   // If already the delegate, there is nothing else to do.
   if (multidevice_setup_ptr_)
@@ -199,40 +243,17 @@
   binding_.Bind(mojo::MakeRequest(&delegate_ptr));
   multidevice_setup_ptr_->SetAccountStatusChangeDelegate(
       std::move(delegate_ptr));
-}
 
-void MultiDeviceNotificationPresenter::OnNotificationClicked() {
-  DCHECK(notification_status_ != Status::kNoNotificationVisible);
-  PA_LOG(INFO) << "User clicked "
-               << GetNotificationDescriptionForLogging(notification_status_)
-               << ".";
-  UMA_HISTOGRAM_ENUMERATION("MultiDeviceSetup_NotificationClicked",
-                            GetMetricValueForNotification(notification_status_),
-                            kNotificationTypeMax);
-  switch (notification_status_) {
-    case Status::kNewUserNotificationVisible:
-      open_ui_delegate_->OpenMultiDeviceSetupUi();
-      break;
-    case Status::kExistingUserHostSwitchedNotificationVisible:
-      // Clicks on the 'host switched' and 'Chromebook added' notifications have
-      // the same effect, i.e. opening the Settings subpage.
-      FALLTHROUGH;
-    case Status::kExistingUserNewChromebookNotificationVisible:
-      open_ui_delegate_->OpenConnectedDevicesSettings();
-      break;
-    case Status::kNoNotificationVisible:
-      NOTREACHED();
-  }
-  RemoveMultiDeviceSetupNotification();
+  message_center_->AddObserver(this);
 }
 
 void MultiDeviceNotificationPresenter::ShowNotification(
     const Status notification_status,
     const base::string16& title,
     const base::string16& message) {
-  PA_LOG(INFO) << "Showing "
-               << GetNotificationDescriptionForLogging(notification_status)
-               << ".";
+  PA_LOG(VERBOSE) << "Showing "
+                  << GetNotificationDescriptionForLogging(notification_status)
+                  << ".";
   UMA_HISTOGRAM_ENUMERATION("MultiDeviceSetup_NotificationShown",
                             GetMetricValueForNotification(notification_status),
                             kNotificationTypeMax);
@@ -249,17 +270,13 @@
 MultiDeviceNotificationPresenter::CreateNotification(
     const base::string16& title,
     const base::string16& message) {
-  return message_center::Notification::CreateSystemNotification(
+  return ash::CreateSystemNotification(
       message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE,
       kNotificationId, title, message, base::string16() /* display_source */,
       GURL() /* origin_url */,
-      message_center::NotifierId(
-          message_center::NotifierId::NotifierType::SYSTEM_COMPONENT,
-          kNotifierMultiDevice),
-      message_center::RichNotificationData(),
-      new message_center::HandleNotificationClickDelegate(base::BindRepeating(
-          &MultiDeviceNotificationPresenter::OnNotificationClicked,
-          weak_ptr_factory_.GetWeakPtr())),
+      message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
+                                 kNotifierMultiDevice),
+      message_center::RichNotificationData(), nullptr /* delegate */,
       ash::kNotificationMultiDeviceSetupIcon,
       message_center::SystemNotificationWarningLevel::NORMAL);
 }
diff --git a/ash/multi_device_setup/multi_device_notification_presenter.h b/ash/multi_device_setup/multi_device_notification_presenter.h
index 14cbbe8..4d9571f 100644
--- a/ash/multi_device_setup/multi_device_notification_presenter.h
+++ b/ash/multi_device_setup/multi_device_notification_presenter.h
@@ -15,6 +15,7 @@
 #include "base/strings/string16.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "ui/message_center/message_center_observer.h"
 
 namespace message_center {
 class MessageCenter;
@@ -43,7 +44,8 @@
 // old text is replaced (if it's different) and the notification pops up again.
 class ASH_EXPORT MultiDeviceNotificationPresenter
     : public chromeos::multidevice_setup::mojom::AccountStatusChangeDelegate,
-      public SessionObserver {
+      public SessionObserver,
+      public message_center::MessageCenterObserver {
  public:
   MultiDeviceNotificationPresenter(
       message_center::MessageCenter* message_center,
@@ -67,6 +69,15 @@
   void OnUserSessionAdded(const AccountId& account_id) override;
   void OnSessionStateChanged(session_manager::SessionState state) override;
 
+  // message_center::MessageCenterObserver
+  void OnNotificationRemoved(const std::string& notification_id,
+                             bool by_user) override;
+
+  void OnNotificationClicked(
+      const std::string& notification_id,
+      const base::Optional<int>& button_index,
+      const base::Optional<base::string16>& reply) override;
+
  private:
   friend class MultiDeviceNotificationPresenterTest;
 
@@ -109,7 +120,6 @@
       Status notification_status);
 
   void ObserveMultiDeviceSetupIfPossible();
-  void OnNotificationClicked();
   void ShowNotification(const Status notification_status,
                         const base::string16& title,
                         const base::string16& message);
diff --git a/ash/multi_device_setup/multi_device_notification_presenter_unittest.cc b/ash/multi_device_setup/multi_device_notification_presenter_unittest.cc
index c77e6b6d..5fc03b6 100644
--- a/ash/multi_device_setup/multi_device_notification_presenter_unittest.cc
+++ b/ash/multi_device_setup/multi_device_notification_presenter_unittest.cc
@@ -60,6 +60,8 @@
     EXPECT_TRUE(notification_);
     EXPECT_EQ(notification_->id(), id);
     notification_.reset();
+    for (auto& observer : observer_list())
+      observer.OnNotificationRemoved(id, by_user);
   }
 
   message_center::Notification* FindVisibleNotificationById(
@@ -74,7 +76,8 @@
   void ClickOnNotification(const std::string& id) override {
     EXPECT_TRUE(notification_);
     EXPECT_EQ(id, notification_->id());
-    notification_->delegate()->Click(base::nullopt, base::nullopt);
+    for (auto& observer : observer_list())
+      observer.OnNotificationClicked(id, base::nullopt, base::nullopt);
   }
 
  private:
@@ -200,6 +203,11 @@
         MultiDeviceNotificationPresenter::kNotificationId);
   }
 
+  void DismissNotification(bool by_user) {
+    test_message_center_.RemoveNotification(
+        MultiDeviceNotificationPresenter::kNotificationId, by_user);
+  }
+
   void VerifyNewUserPotentialHostExistsNotificationIsVisible() {
     VerifyNotificationIsVisible(
         MultiDeviceNotificationPresenter::Status::kNewUserNotificationVisible);
@@ -359,6 +367,29 @@
   AssertPotentialHostBucketCount("MultiDeviceSetup_NotificationShown", 1);
 }
 
+TEST_F(MultiDeviceNotificationPresenterTest,
+       TestHostNewUserPotentialHostExistsNotification_DismissedNotification) {
+  SignIntoAccount();
+
+  ShowNewUserNotification();
+  VerifyNewUserPotentialHostExistsNotificationIsVisible();
+
+  DismissNotification(true /* by_user */);
+  VerifyNoNotificationIsVisible();
+
+  EXPECT_EQ(test_open_ui_delegate_->open_multi_device_setup_ui_count(), 0);
+  AssertPotentialHostBucketCount("MultiDeviceSetup_NotificationDismissed", 1);
+
+  ShowNewUserNotification();
+  VerifyNewUserPotentialHostExistsNotificationIsVisible();
+
+  DismissNotification(false /* by_user */);
+  VerifyNoNotificationIsVisible();
+
+  EXPECT_EQ(test_open_ui_delegate_->open_multi_device_setup_ui_count(), 0);
+  AssertPotentialHostBucketCount("MultiDeviceSetup_NotificationDismissed", 1);
+}
+
 TEST_F(MultiDeviceNotificationPresenterTest, TestNoLongerNewUserEvent) {
   SignIntoAccount();
 
@@ -403,6 +434,29 @@
   AssertHostSwitchedBucketCount("MultiDeviceSetup_NotificationShown", 1);
 }
 
+TEST_F(MultiDeviceNotificationPresenterTest,
+       TestHostExistingUserHostSwitchedNotification_DismissedNotification) {
+  SignIntoAccount();
+
+  ShowExistingUserHostSwitchedNotification();
+  VerifyExistingUserHostSwitchedNotificationIsVisible();
+
+  DismissNotification(true /* by_user */);
+  VerifyNoNotificationIsVisible();
+
+  EXPECT_EQ(test_open_ui_delegate_->open_multi_device_setup_ui_count(), 0);
+  AssertHostSwitchedBucketCount("MultiDeviceSetup_NotificationDismissed", 1);
+
+  ShowExistingUserHostSwitchedNotification();
+  VerifyExistingUserHostSwitchedNotificationIsVisible();
+
+  DismissNotification(false /* by_user */);
+  VerifyNoNotificationIsVisible();
+
+  EXPECT_EQ(test_open_ui_delegate_->open_multi_device_setup_ui_count(), 0);
+  AssertHostSwitchedBucketCount("MultiDeviceSetup_NotificationDismissed", 1);
+}
+
 TEST_F(
     MultiDeviceNotificationPresenterTest,
     TestHostExistingUserNewChromebookAddedNotification_RemoveProgrammatically) {
@@ -434,6 +488,30 @@
   AssertNewChromebookBucketCount("MultiDeviceSetup_NotificationShown", 1);
 }
 
+TEST_F(
+    MultiDeviceNotificationPresenterTest,
+    TestHostExistingUserNewChromebookAddedNotification_DismissedNotification) {
+  SignIntoAccount();
+
+  ShowExistingUserNewChromebookNotification();
+  VerifyExistingUserNewChromebookAddedNotificationIsVisible();
+
+  DismissNotification(true /* by_user */);
+  VerifyNoNotificationIsVisible();
+
+  EXPECT_EQ(test_open_ui_delegate_->open_multi_device_setup_ui_count(), 0);
+  AssertNewChromebookBucketCount("MultiDeviceSetup_NotificationDismissed", 1);
+
+  ShowExistingUserNewChromebookNotification();
+  VerifyExistingUserNewChromebookAddedNotificationIsVisible();
+
+  DismissNotification(false /* by_user */);
+  VerifyNoNotificationIsVisible();
+
+  EXPECT_EQ(test_open_ui_delegate_->open_multi_device_setup_ui_count(), 0);
+  AssertNewChromebookBucketCount("MultiDeviceSetup_NotificationDismissed", 1);
+}
+
 TEST_F(MultiDeviceNotificationPresenterTest, NotificationsReplaceOneAnother) {
   SignIntoAccount();
 
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index edf9730..f9881a6 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -47,6 +47,10 @@
     "ash_typography.cc",
     "ash_typography.h",
     "ash_view_ids.h",
+    "assistant/assistant_state_base.cc",
+    "assistant/assistant_state_base.h",
+    "assistant/assistant_state_proxy.cc",
+    "assistant/assistant_state_proxy.h",
     "assistant/default_voice_interaction_observer.h",
     "caption_buttons/caption_button_model.h",
     "caption_buttons/caption_button_types.h",
@@ -75,9 +79,6 @@
     "immersive/immersive_fullscreen_controller.cc",
     "immersive/immersive_fullscreen_controller.h",
     "immersive/immersive_fullscreen_controller_delegate.h",
-    "immersive/immersive_gesture_handler.h",
-    "immersive/immersive_handler_factory.cc",
-    "immersive/immersive_handler_factory.h",
     "immersive/immersive_revealed_lock.cc",
     "immersive/immersive_revealed_lock.h",
     "login_constants.h",
@@ -87,6 +88,8 @@
     "mus_property_mirror_ash.h",
     "network_icon_image_source.cc",
     "network_icon_image_source.h",
+    "notification_utils.cc",
+    "notification_utils.h",
     "power_utils.cc",
     "power_utils.h",
     "remote_shelf_item_delegate.cc",
@@ -127,12 +130,14 @@
     "//ash/public/cpp/vector_icons",
     "//chromeos:power_manager_proto",
     "//components/prefs",
+    "//services/service_manager/public/cpp",
     "//services/ws/public/mojom",
     "//skia/public/interfaces",
     "//ui/aura",
     "//ui/chromeos/strings",
     "//ui/display",
     "//ui/events/devices",
+    "//ui/message_center/public/cpp",
     "//ui/views",
     "//ui/views/mus",
     "//ui/wm",
@@ -155,6 +160,7 @@
 # this after Deserialize(Serialize()) API works with handles.
 mojom("test_interfaces") {
   visibility = [ ":unit_tests" ]
+  disable_variants = true
 
   sources = [
     "shelf_struct_traits_test_service.mojom",
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc
index 5dcc9a2..f46880a3 100644
--- a/ash/public/cpp/app_list/app_list_features.cc
+++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -13,7 +13,7 @@
 const base::Feature kEnableAnswerCard{"EnableAnswerCard",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kEnableAppShortcutSearch{"EnableAppShortcutSearch",
-                                             base::FEATURE_DISABLED_BY_DEFAULT};
+                                             base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kEnableBackgroundBlur{"EnableBackgroundBlur",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kEnablePlayStoreAppSearch{
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index bd1fcee..47ec75a 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -93,10 +93,6 @@
   return base::FeatureList::IsEnabled(kNotificationScrollBar);
 }
 
-bool IsSystemTrayUnifiedEnabled() {
-  return true;
-}
-
 bool IsTrilinearFilteringEnabled() {
   static bool use_trilinear_filtering =
       base::FeatureList::IsEnabled(kTrilinearFiltering);
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index 3966fb2..25f14c4 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -96,8 +96,6 @@
 
 ASH_PUBLIC_EXPORT bool IsNotificationScrollBarEnabled();
 
-ASH_PUBLIC_EXPORT bool IsSystemTrayUnifiedEnabled();
-
 ASH_PUBLIC_EXPORT bool IsTrilinearFilteringEnabled();
 
 ASH_PUBLIC_EXPORT bool IsViewsLoginEnabled();
diff --git a/ash/public/cpp/ash_switches.cc b/ash/public/cpp/ash_switches.cc
index 322e556..b83352173 100644
--- a/ash/public/cpp/ash_switches.cc
+++ b/ash/public/cpp/ash_switches.cc
@@ -63,10 +63,6 @@
 // Enables mirrored screen.
 const char kAshEnableMirroredScreen[] = "ash-enable-mirrored-screen";
 
-// Enables display scale tray settings. This uses force-device-scale-factor flag
-// to modify the dsf of the device to any non discrete value.
-const char kAshEnableScaleSettingsTray[] = "ash-enable-scale-settings-tray";
-
 // Enables the stylus tools next to the status area.
 const char kAshForceEnableStylusTools[] = "force-enable-stylus-tools";
 
diff --git a/ash/public/cpp/ash_switches.h b/ash/public/cpp/ash_switches.h
index 670b12c..6dbf942a 100644
--- a/ash/public/cpp/ash_switches.h
+++ b/ash/public/cpp/ash_switches.h
@@ -27,7 +27,6 @@
 ASH_PUBLIC_EXPORT extern const char kAshEnableV1AppBackButton[];
 ASH_PUBLIC_EXPORT extern const char kAshEnableMagnifierKeyScroller[];
 ASH_PUBLIC_EXPORT extern const char kAshEnablePaletteOnAllDisplays[];
-ASH_PUBLIC_EXPORT extern const char kAshEnableScaleSettingsTray[];
 ASH_PUBLIC_EXPORT extern const char kAshEnableTabletMode[];
 ASH_PUBLIC_EXPORT extern const char kAshEnableWaylandServer[];
 ASH_PUBLIC_EXPORT extern const char kAshEnableMirroredScreen[];
diff --git a/ash/public/cpp/ash_view_ids.h b/ash/public/cpp/ash_view_ids.h
index 9b558d2..089045f 100644
--- a/ash/public/cpp/ash_view_ids.h
+++ b/ash/public/cpp/ash_view_ids.h
@@ -13,6 +13,11 @@
   // Ash IDs start above the range used in Chrome (c/b/ui/view_ids.h).
   VIEW_ID_ASH_START = 10000,
 
+  // Row for auto click feature in accessibility detailed view.
+  VIEW_ID_ACCESSIBILITY_AUTOCLICK,
+  // Icon that indicates auto click is enabled.
+  VIEW_ID_ACCESSIBILITY_AUTOCLICK_ENABLED,
+  // Accessibility feature pod button in main view.
   VIEW_ID_ACCESSIBILITY_TRAY_ITEM,
   VIEW_ID_BLUETOOTH_DEFAULT_VIEW,
   // System tray casting row elements.
diff --git a/ash/public/cpp/assistant/assistant_state_base.cc b/ash/public/cpp/assistant/assistant_state_base.cc
new file mode 100644
index 0000000..0d0bdc8
--- /dev/null
+++ b/ash/public/cpp/assistant/assistant_state_base.cc
@@ -0,0 +1,13 @@
+// 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/public/cpp/assistant/assistant_state_base.h"
+
+namespace ash {
+
+AssistantStateBase::AssistantStateBase() = default;
+
+AssistantStateBase::~AssistantStateBase() = default;
+
+}  // namespace ash
diff --git a/ash/public/cpp/assistant/assistant_state_base.h b/ash/public/cpp/assistant/assistant_state_base.h
new file mode 100644
index 0000000..016d968
--- /dev/null
+++ b/ash/public/cpp/assistant/assistant_state_base.h
@@ -0,0 +1,78 @@
+// 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_PUBLIC_CPP_ASSISTANT_ASSISTANT_STATE_BASE_H_
+#define ASH_PUBLIC_CPP_ASSISTANT_ASSISTANT_STATE_BASE_H_
+
+#include <string>
+
+#include "ash/public/interfaces/voice_interaction_controller.mojom.h"
+#include "base/macros.h"
+#include "base/optional.h"
+
+namespace ash {
+
+// Plain data class that holds Assistant related prefs and states. This is
+// shared by both the controller that controlls these values and client proxy
+// that caches these values locally. Please do not use this object directly,
+// most likely you want to use |AssistantStateProxy|.
+class ASH_PUBLIC_EXPORT AssistantStateBase {
+ public:
+  AssistantStateBase();
+  virtual ~AssistantStateBase();
+
+  const base::Optional<mojom::VoiceInteractionState>& voice_interaction_state()
+      const {
+    return voice_interaction_state_;
+  }
+
+  const base::Optional<bool>& settings_enabled() const {
+    return settings_enabled_;
+  }
+
+  const base::Optional<bool>& setup_completed() const {
+    return setup_completed_;
+  }
+
+  const base::Optional<bool>& context_enabled() const {
+    return context_enabled_;
+  }
+
+  const base::Optional<bool>& hotword_enabled() const {
+    return hotword_enabled_;
+  }
+
+  const base::Optional<mojom::AssistantAllowedState>& allowed_state() const {
+    return allowed_state_;
+  }
+
+  const base::Optional<std::string>& locale() const { return locale_; }
+
+ protected:
+  base::Optional<mojom::VoiceInteractionState> voice_interaction_state_;
+
+  // Whether voice interaction is enabled in system settings.
+  base::Optional<bool> settings_enabled_;
+
+  // Whether voice interaction setup flow has completed.
+  base::Optional<bool> setup_completed_;
+
+  // Whether screen context is enabled.
+  base::Optional<bool> context_enabled_;
+
+  // Whether hotword listening is enabled.
+  base::Optional<bool> hotword_enabled_;
+
+  // Whether voice interaction feature is allowed or disallowed for what reason.
+  base::Optional<mojom::AssistantAllowedState> allowed_state_;
+
+  base::Optional<std::string> locale_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AssistantStateBase);
+};
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_ASSISTANT_ASSISTANT_STATE_BASE_H_
diff --git a/ash/public/cpp/assistant/assistant_state_proxy.cc b/ash/public/cpp/assistant/assistant_state_proxy.cc
new file mode 100644
index 0000000..bcf208f
--- /dev/null
+++ b/ash/public/cpp/assistant/assistant_state_proxy.cc
@@ -0,0 +1,97 @@
+// 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 <algorithm>
+#include <utility>
+
+#include "ash/public/cpp/assistant/assistant_state_proxy.h"
+#include "ash/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace ash {
+
+AssistantStateProxy::AssistantStateProxy()
+    : voice_interaction_observer_binding_(this) {}
+
+AssistantStateProxy::~AssistantStateProxy() = default;
+
+void AssistantStateProxy::Init(service_manager::Connector* connector) {
+  connector->BindInterface(ash::mojom::kServiceName,
+                           &voice_interaction_controller_);
+
+  ash::mojom::VoiceInteractionObserverPtr ptr;
+  voice_interaction_observer_binding_.Bind(mojo::MakeRequest(&ptr));
+  voice_interaction_controller_->AddObserver(std::move(ptr));
+}
+
+void AssistantStateProxy::AddObserver(
+    DefaultVoiceInteractionObserver* observer) {
+  if (voice_interaction_state_.has_value())
+    observer->OnVoiceInteractionStatusChanged(voice_interaction_state_.value());
+  if (settings_enabled_.has_value())
+    observer->OnVoiceInteractionSettingsEnabled(settings_enabled_.value());
+  if (context_enabled_.has_value())
+    observer->OnVoiceInteractionContextEnabled(context_enabled_.value());
+  if (hotword_enabled_.has_value())
+    observer->OnVoiceInteractionHotwordEnabled(hotword_enabled_.value());
+  if (setup_completed_.has_value())
+    observer->OnVoiceInteractionSetupCompleted(setup_completed_.value());
+  if (allowed_state_.has_value())
+    observer->OnAssistantFeatureAllowedChanged(allowed_state_.value());
+  if (locale_.has_value())
+    observer->OnLocaleChanged(locale_.value());
+
+  observers_.AddObserver(observer);
+}
+
+void AssistantStateProxy::RemoveObserver(
+    DefaultVoiceInteractionObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void AssistantStateProxy::OnVoiceInteractionStatusChanged(
+    ash::mojom::VoiceInteractionState state) {
+  voice_interaction_state_ = state;
+  for (auto& observer : observers_)
+    observer.OnVoiceInteractionStatusChanged(voice_interaction_state_.value());
+}
+
+void AssistantStateProxy::OnVoiceInteractionSettingsEnabled(bool enabled) {
+  settings_enabled_ = enabled;
+  for (auto& observer : observers_)
+    observer.OnVoiceInteractionSettingsEnabled(settings_enabled_.value());
+}
+
+void AssistantStateProxy::OnVoiceInteractionContextEnabled(bool enabled) {
+  context_enabled_ = enabled;
+  for (auto& observer : observers_)
+    observer.OnVoiceInteractionContextEnabled(context_enabled_.value());
+}
+
+void AssistantStateProxy::OnVoiceInteractionHotwordEnabled(bool enabled) {
+  hotword_enabled_ = enabled;
+  for (auto& observer : observers_)
+    observer.OnVoiceInteractionHotwordEnabled(hotword_enabled_.value());
+}
+
+void AssistantStateProxy::OnVoiceInteractionSetupCompleted(bool completed) {
+  setup_completed_ = completed;
+  for (auto& observer : observers_)
+    observer.OnVoiceInteractionSetupCompleted(setup_completed_.value());
+}
+
+void AssistantStateProxy::OnAssistantFeatureAllowedChanged(
+    ash::mojom::AssistantAllowedState state) {
+  allowed_state_ = state;
+  for (auto& observer : observers_)
+    observer.OnAssistantFeatureAllowedChanged(allowed_state_.value());
+}
+
+void AssistantStateProxy::OnLocaleChanged(const std::string& locale) {
+  locale_ = locale;
+  for (auto& observer : observers_)
+    observer.OnLocaleChanged(locale_.value());
+}
+
+}  // namespace ash
diff --git a/ash/public/cpp/assistant/assistant_state_proxy.h b/ash/public/cpp/assistant/assistant_state_proxy.h
new file mode 100644
index 0000000..b2a7e6b1
--- /dev/null
+++ b/ash/public/cpp/assistant/assistant_state_proxy.h
@@ -0,0 +1,63 @@
+// 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_PUBLIC_CPP_ASSISTANT_ASSISTANT_STATE_PROXY_H_
+#define ASH_PUBLIC_CPP_ASSISTANT_ASSISTANT_STATE_PROXY_H_
+
+#include <string>
+#include <vector>
+
+#include "ash/public/cpp/assistant/assistant_state_base.h"
+#include "ash/public/cpp/assistant/default_voice_interaction_observer.h"
+#include "ash/public/interfaces/voice_interaction_controller.mojom.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace service_manager {
+class Connector;
+}  // namespace service_manager
+
+namespace ash {
+
+// Provides a convenient client to access various Assistant states. The state
+// infomration can be accessed through direct accessors which returns
+// |base::Optional<>| or observers. When adding an observer, all change events
+// will fire if this client already have data.
+class ASH_PUBLIC_EXPORT AssistantStateProxy
+    : public AssistantStateBase,
+      public mojom::VoiceInteractionObserver {
+ public:
+  AssistantStateProxy();
+  ~AssistantStateProxy() override;
+
+  void Init(service_manager::Connector* connector);
+  void AddObserver(DefaultVoiceInteractionObserver* observer);
+  void RemoveObserver(DefaultVoiceInteractionObserver* observer);
+
+ private:
+  // mojom::VoiceInteractionObserver:
+  void OnVoiceInteractionStatusChanged(
+      ash::mojom::VoiceInteractionState state) override;
+  void OnVoiceInteractionSettingsEnabled(bool enabled) override;
+  void OnVoiceInteractionContextEnabled(bool enabled) override;
+  void OnVoiceInteractionHotwordEnabled(bool enabled) override;
+  void OnVoiceInteractionSetupCompleted(bool completed) override;
+  void OnAssistantFeatureAllowedChanged(
+      ash::mojom::AssistantAllowedState state) override;
+  void OnLocaleChanged(const std::string& locale) override;
+
+  base::ObserverList<DefaultVoiceInteractionObserver> observers_;
+
+  ash::mojom::VoiceInteractionControllerPtr voice_interaction_controller_;
+  mojo::Binding<ash::mojom::VoiceInteractionObserver>
+      voice_interaction_observer_binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(AssistantStateProxy);
+};
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_ASSISTANT_ASSISTANT_STATE_PROXY_H_
diff --git a/ash/public/cpp/assistant/default_voice_interaction_observer.h b/ash/public/cpp/assistant/default_voice_interaction_observer.h
index e511109..255d6ca4 100644
--- a/ash/public/cpp/assistant/default_voice_interaction_observer.h
+++ b/ash/public/cpp/assistant/default_voice_interaction_observer.h
@@ -9,6 +9,7 @@
 
 #include "ash/public/interfaces/voice_interaction_controller.mojom.h"
 #include "base/macros.h"
+#include "base/observer_list_types.h"
 
 namespace ash {
 
@@ -16,7 +17,8 @@
 // ash::mojom::VoiceInteractionObserver interface. Child class only need to
 // override the methods they are actually interested in.
 class ASH_PUBLIC_EXPORT DefaultVoiceInteractionObserver
-    : public mojom::VoiceInteractionObserver {
+    : public mojom::VoiceInteractionObserver,
+      public base::CheckedObserver {
  public:
   ~DefaultVoiceInteractionObserver() override = default;
 
diff --git a/ash/public/cpp/immersive/immersive_context.h b/ash/public/cpp/immersive/immersive_context.h
index eaab141..00dea65 100644
--- a/ash/public/cpp/immersive/immersive_context.h
+++ b/ash/public/cpp/immersive/immersive_context.h
@@ -39,9 +39,6 @@
 
   // Returns true if any window has capture.
   virtual bool DoesAnyWindowHaveCapture() = 0;
-
-  // See Shell::IsMouseEventsEnabled() for details.
-  virtual bool IsMouseEventsEnabled() = 0;
 };
 
 }  // namespace ash
diff --git a/ash/public/cpp/immersive/immersive_fullscreen_controller.cc b/ash/public/cpp/immersive/immersive_fullscreen_controller.cc
index 76acdbc7..ff40a3b 100644
--- a/ash/public/cpp/immersive/immersive_fullscreen_controller.cc
+++ b/ash/public/cpp/immersive/immersive_fullscreen_controller.cc
@@ -9,13 +9,13 @@
 #include "ash/public/cpp/immersive/immersive_context.h"
 #include "ash/public/cpp/immersive/immersive_focus_watcher.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
-#include "ash/public/cpp/immersive/immersive_gesture_handler.h"
-#include "ash/public/cpp/immersive/immersive_handler_factory.h"
 #include "ash/public/cpp/window_properties.h"
 #include "base/metrics/histogram_macros.h"
+#include "ui/aura/client/cursor_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_targeter.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 #include "ui/events/base_event_utils.h"
@@ -126,45 +126,28 @@
                                    animate_reveal);
 }
 
-////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// ui::EventObserver overrides:
 
-void ImmersiveFullscreenController::OnMouseEvent(
-    const ui::MouseEvent& event,
-    const gfx::Point& location_in_screen,
-    views::Widget* target) {
-  if (!enabled_)
+void ImmersiveFullscreenController::OnEvent(const ui::Event& event) {
+  if (!event.IsLocatedEvent())
     return;
 
-  if (event.type() != ui::ET_MOUSE_MOVED &&
-      event.type() != ui::ET_MOUSE_PRESSED &&
-      event.type() != ui::ET_MOUSE_RELEASED &&
-      event.type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
-    return;
-  }
-
-  // Mouse hover can initiate revealing the top-of-window views while |widget_|
-  // is inactive.
-  if (reveal_state_ == SLIDING_OPEN || reveal_state_ == REVEALED) {
-    top_edge_hover_timer_.Stop();
-    UpdateLocatedEventRevealedLock(&event, location_in_screen);
-  } else if (event.type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
-    // Trigger reveal if the cursor pauses at the top of the screen for a while.
-    UpdateTopEdgeHoverTimer(event, location_in_screen, target);
+  const ui::LocatedEvent* located_event = event.AsLocatedEvent();
+  aura::Window* target = static_cast<aura::Window*>(event.target());
+  if (event.IsMouseEvent()) {
+    HandleMouseEvent(*event.AsMouseEvent(), located_event->root_location(),
+                     views::Widget::GetTopLevelWidgetForNativeView(target));
+  } else if (event.IsTouchEvent()) {
+    HandleTouchEvent(*event.AsTouchEvent(), located_event->root_location());
   }
 }
 
-void ImmersiveFullscreenController::OnTouchEvent(
-    const ui::TouchEvent& event,
-    const gfx::Point& location_in_screen) {
-  if (!enabled_ || event.type() != ui::ET_TOUCH_PRESSED)
-    return;
+////////////////////////////////////////////////////////////////////////////////
+// ui::EventHandler overrides:
 
-  // Touch should not initiate revealing the top-of-window views while |widget_|
-  // is inactive.
-  if (!widget_->IsActive())
-    return;
-
-  UpdateLocatedEventRevealedLock(&event, location_in_screen);
+void ImmersiveFullscreenController::OnEvent(ui::Event* event) {
+  ui::EventHandler::OnEvent(event);
 }
 
 void ImmersiveFullscreenController::OnGestureEvent(ui::GestureEvent* event) {
@@ -202,20 +185,6 @@
   }
 }
 
-void ImmersiveFullscreenController::OnEvent(const ui::Event& event) {
-  if (!event.IsLocatedEvent())
-    return;
-
-  const ui::LocatedEvent* located_event = event.AsLocatedEvent();
-  aura::Window* target = static_cast<aura::Window*>(event.target());
-  if (event.IsMouseEvent()) {
-    OnMouseEvent(*event.AsMouseEvent(), located_event->root_location(),
-                 views::Widget::GetTopLevelWidgetForNativeView(target));
-  } else if (event.IsTouchEvent()) {
-    OnTouchEvent(*event.AsTouchEvent(), located_event->root_location());
-  }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // aura::WindowObserver overrides:
 
@@ -297,7 +266,9 @@
 // static
 void ImmersiveFullscreenController::EnableForWidget(views::Widget* widget,
                                                     bool enabled) {
-  widget->GetNativeWindow()->SetProperty(kImmersiveIsActive, enabled);
+  auto* window = widget->GetNativeWindow();
+  if (window->GetProperty(kImmersiveIsActive) != enabled)
+    widget->GetNativeWindow()->SetProperty(kImmersiveIsActive, enabled);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -324,24 +295,66 @@
     return;
   event_observers_enabled_ = enable;
 
-  aura::Env* env = widget_->GetNativeWindow()->env();
+  aura::Window* window = widget_->GetNativeWindow();
+  // For Mash, handle events sent to the Mus client's root window.
+  if (features::IsUsingWindowService())
+    window = window->GetRootWindow();
+  aura::Env* env = window->env();
   if (enable) {
     immersive_focus_watcher_ = std::make_unique<ImmersiveFocusWatcher>(this);
-    immersive_gesture_handler_ =
-        ImmersiveHandlerFactory::Get()->CreateGestureHandler(this);
     std::set<ui::EventType> types = {
         ui::ET_MOUSE_MOVED, ui::ET_MOUSE_PRESSED,         ui::ET_MOUSE_RELEASED,
         ui::ET_MOUSEWHEEL,  ui::ET_MOUSE_CAPTURE_CHANGED, ui::ET_TOUCH_PRESSED};
     env->AddEventObserver(this, env, types);
+    window->AddPreTargetHandler(this);
   } else {
+    window->RemovePreTargetHandler(this);
     env->RemoveEventObserver(this);
-    immersive_gesture_handler_.reset();
     immersive_focus_watcher_.reset();
 
     animation_.Stop();
   }
 }
 
+void ImmersiveFullscreenController::HandleMouseEvent(
+    const ui::MouseEvent& event,
+    const gfx::Point& location_in_screen,
+    views::Widget* target) {
+  if (!enabled_)
+    return;
+
+  if (event.type() != ui::ET_MOUSE_MOVED &&
+      event.type() != ui::ET_MOUSE_PRESSED &&
+      event.type() != ui::ET_MOUSE_RELEASED &&
+      event.type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
+    return;
+  }
+
+  // Mouse hover can initiate revealing the top-of-window views while |widget_|
+  // is inactive.
+  if (reveal_state_ == SLIDING_OPEN || reveal_state_ == REVEALED) {
+    top_edge_hover_timer_.Stop();
+    UpdateLocatedEventRevealedLock(&event, location_in_screen);
+  } else if (event.type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
+    // Trigger reveal if the cursor pauses at the top of the screen for a while.
+    UpdateTopEdgeHoverTimer(event, location_in_screen, target);
+  }
+}
+
+void ImmersiveFullscreenController::HandleTouchEvent(
+    const ui::TouchEvent& event,
+    const gfx::Point& location_in_screen) {
+  if (!enabled_ || event.type() != ui::ET_TOUCH_PRESSED)
+    return;
+
+  // Touch should not initiate revealing the top-of-window views while |widget_|
+  // is inactive.
+  if (!widget_->IsActive())
+    return;
+
+  UpdateLocatedEventRevealedLock(&event, location_in_screen);
+}
+
 void ImmersiveFullscreenController::UpdateTopEdgeHoverTimer(
     const ui::MouseEvent& event,
     const gfx::Point& location_in_screen,
@@ -402,7 +415,7 @@
 
   // Neither the mouse nor touch can initiate a reveal when the top-of-window
   // views are sliding closed or are closed with the following exceptions:
-  // - Hovering at y = 0 which is handled in OnMouseEvent().
+  // - Hovering at y = 0 which is handled in HandleMouseEvent().
   // - Doing a SWIPE_OPEN edge gesture which is handled in OnGestureEvent().
   if (reveal_state_ == CLOSED || reveal_state_ == SLIDING_CLOSED)
     return;
@@ -451,9 +464,11 @@
 }
 
 void ImmersiveFullscreenController::UpdateLocatedEventRevealedLock() {
-  if (!immersive_context_->IsMouseEventsEnabled()) {
+  if (!aura::client::GetCursorClient(
+           widget_->GetNativeWindow()->GetRootWindow())
+           ->IsMouseEventsEnabled()) {
     // If mouse events are disabled, the user's last interaction was probably
-    // via touch. Do no do further processing in this case as there is no easy
+    // via touch. Do no further processing in this case as there is no easy
     // way of retrieving the position of the user's last touch.
     return;
   }
diff --git a/ash/public/cpp/immersive/immersive_fullscreen_controller.h b/ash/public/cpp/immersive/immersive_fullscreen_controller.h
index b604907..312f97f 100644
--- a/ash/public/cpp/immersive/immersive_fullscreen_controller.h
+++ b/ash/public/cpp/immersive/immersive_fullscreen_controller.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/timer/timer.h"
 #include "ui/aura/window_observer.h"
+#include "ui/events/event_handler.h"
 #include "ui/events/event_observer.h"
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/animation/slide_animation.h"
@@ -45,12 +46,12 @@
 class ImmersiveFocusWatcher;
 class ImmersiveFullscreenControllerDelegate;
 class ImmersiveFullscreenControllerTestApi;
-class ImmersiveGestureHandler;
 
 class ASH_PUBLIC_EXPORT ImmersiveFullscreenController
     : public aura::WindowObserver,
       public gfx::AnimationDelegate,
       public ui::EventObserver,
+      public ui::EventHandler,
       public views::ViewObserver,
       public ImmersiveRevealedLock::Delegate {
  public:
@@ -109,18 +110,13 @@
   views::Widget* widget() { return widget_; }
   views::View* top_container() { return top_container_; }
 
-  // TODO(sky): move OnMouseEvent/OnTouchEvent to private section.
-  void OnMouseEvent(const ui::MouseEvent& event,
-                    const gfx::Point& location_in_screen,
-                    views::Widget* target);
-  void OnTouchEvent(const ui::TouchEvent& event,
-                    const gfx::Point& location_in_screen);
-  // Processes a GestureEvent. This may call SetHandled() on the supplied event.
-  void OnGestureEvent(ui::GestureEvent* event);
-
   // ui::EventObserver:
   void OnEvent(const ui::Event& event) override;
 
+  // ui::EventHandler:
+  void OnEvent(ui::Event* event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
+
   // aura::WindowObserver:
   void OnWindowPropertyChanged(aura::Window* window,
                                const void* key,
@@ -165,6 +161,13 @@
   // Enables or disables observers for mouse, touch, focus, and activation.
   void EnableEventObservers(bool enable);
 
+  // Called to handle EventObserver::OnEvent.
+  void HandleMouseEvent(const ui::MouseEvent& event,
+                        const gfx::Point& location_in_screen,
+                        views::Widget* target);
+  void HandleTouchEvent(const ui::TouchEvent& event,
+                        const gfx::Point& location_in_screen);
+
   // Updates |top_edge_hover_timer_| based on a mouse |event|. If the mouse is
   // hovered at the top of the screen the timer is started. If the mouse moves
   // away from the top edge, or moves too much in the x direction, the timer is
@@ -289,7 +292,6 @@
   bool animations_disabled_for_test_;
 
   std::unique_ptr<ImmersiveFocusWatcher> immersive_focus_watcher_;
-  std::unique_ptr<ImmersiveGestureHandler> immersive_gesture_handler_;
 
   // The window targeter that was in use before immersive fullscreen mode was
   // entered, if any. Will be re-installed on the window after leaving immersive
diff --git a/ash/public/cpp/immersive/immersive_gesture_handler.h b/ash/public/cpp/immersive/immersive_gesture_handler.h
deleted file mode 100644
index dc89054..0000000
--- a/ash/public/cpp/immersive/immersive_gesture_handler.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2016 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_IMMERSIVE_IMMERSIVE_GESTURE_HANDLER_H_
-#define ASH_PUBLIC_CPP_IMMERSIVE_IMMERSIVE_GESTURE_HANDLER_H_
-
-#include "ash/public/cpp/ash_public_export.h"
-
-namespace ash {
-
-// ImmersiveGestureHandler is responsible for calling
-// ImmersiveFullscreenController::OnGestureEvent() to show/hide the title bar or
-// TabletAppModeWindowDragController::DragWindowFromTop() to drag the window
-// from the top if CanDragWindow is true when a gesture is received.
-class ASH_PUBLIC_EXPORT ImmersiveGestureHandler {
- public:
-  virtual ~ImmersiveGestureHandler() {}
-};
-
-}  // namespace ash
-
-#endif  // ASH_PUBLIC_CPP_IMMERSIVE_IMMERSIVE_GESTURE_HANDLER_H_
diff --git a/ash/public/cpp/immersive/immersive_handler_factory.cc b/ash/public/cpp/immersive/immersive_handler_factory.cc
deleted file mode 100644
index 6ee501d..0000000
--- a/ash/public/cpp/immersive/immersive_handler_factory.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 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/immersive/immersive_handler_factory.h"
-
-#include "base/logging.h"
-
-namespace ash {
-
-// static
-ImmersiveHandlerFactory* ImmersiveHandlerFactory::instance_ = nullptr;
-
-ImmersiveHandlerFactory::ImmersiveHandlerFactory() {
-  DCHECK(!instance_);
-  instance_ = this;
-}
-
-ImmersiveHandlerFactory::~ImmersiveHandlerFactory() {
-  DCHECK_EQ(instance_, this);
-  instance_ = nullptr;
-}
-
-}  // namespace ash
diff --git a/ash/public/cpp/immersive/immersive_handler_factory.h b/ash/public/cpp/immersive/immersive_handler_factory.h
deleted file mode 100644
index 418153e..0000000
--- a/ash/public/cpp/immersive/immersive_handler_factory.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2016 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_IMMERSIVE_IMMERSIVE_HANDLER_FACTORY_H_
-#define ASH_PUBLIC_CPP_IMMERSIVE_IMMERSIVE_HANDLER_FACTORY_H_
-
-#include <memory>
-
-#include "ash/public/cpp/ash_public_export.h"
-
-namespace ash {
-
-class ImmersiveFullscreenController;
-class ImmersiveGestureHandler;
-
-// Used by ImmersiveFullscreenController to create event handlers/watchers.
-class ASH_PUBLIC_EXPORT ImmersiveHandlerFactory {
- public:
-  static ImmersiveHandlerFactory* Get() { return instance_; }
-
-  virtual std::unique_ptr<ImmersiveGestureHandler> CreateGestureHandler(
-      ImmersiveFullscreenController* controller) = 0;
-
- protected:
-  ImmersiveHandlerFactory();
-  virtual ~ImmersiveHandlerFactory();
-
- private:
-  static ImmersiveHandlerFactory* instance_;
-};
-
-}  // namespace ash
-
-#endif  // ASH_PUBLIC_CPP_IMMERSIVE_IMMERSIVE_HANDLER_FACTORY_H_
diff --git a/ash/public/cpp/menu_struct_mojom_traits.h b/ash/public/cpp/menu_struct_mojom_traits.h
index f168c5e..3abe6627 100644
--- a/ash/public/cpp/menu_struct_mojom_traits.h
+++ b/ash/public/cpp/menu_struct_mojom_traits.h
@@ -31,6 +31,9 @@
         return ash::mojom::MenuItemType::SUBMENU;
       case ui::MenuModel::TYPE_ACTIONABLE_SUBMENU:
         return ash::mojom::MenuItemType::ACTIONABLE_SUBMENU;
+      case ui::MenuModel::TYPE_HIGHLIGHTED:
+        NOTREACHED() << "TYPE_HIGHLIGHTED is not yet supported";
+        return ash::mojom::MenuItemType::COMMAND;
     }
     NOTREACHED();
     return ash::mojom::MenuItemType::COMMAND;
diff --git a/ash/public/cpp/menu_utils.cc b/ash/public/cpp/menu_utils.cc
index ebce149..e06cc16 100644
--- a/ash/public/cpp/menu_utils.cc
+++ b/ash/public/cpp/menu_utils.cc
@@ -77,6 +77,9 @@
           submenus->push_back(std::move(submenu));
         }
         break;
+      case ui::MenuModel::TYPE_HIGHLIGHTED:
+        NOTREACHED() << "TYPE_HIGHLIGHTED is not yet supported.";
+        break;
     }
     if (!item->image.isNull()) {
       model->SetIcon(model->GetIndexOfCommandId(item->command_id),
diff --git a/ash/public/cpp/notification_utils.cc b/ash/public/cpp/notification_utils.cc
new file mode 100644
index 0000000..58fcd46
--- /dev/null
+++ b/ash/public/cpp/notification_utils.cc
@@ -0,0 +1,68 @@
+// 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/public/cpp/notification_utils.h"
+
+#include "ui/gfx/vector_icon_types.h"
+#include "ui/message_center/public/cpp/notification_delegate.h"
+
+namespace ash {
+
+std::unique_ptr<message_center::Notification> CreateSystemNotification(
+    const std::string& notification_id,
+    const base::string16& title,
+    const base::string16& message,
+    const std::string& system_component_id,
+    const base::RepeatingClosure& click_callback) {
+  DCHECK(!click_callback.is_null());
+  std::unique_ptr<message_center::Notification> notification =
+      CreateSystemNotification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
+          message, base::string16() /* display_source */, GURL(),
+          message_center::NotifierId(
+              message_center::NotifierType::SYSTEM_COMPONENT,
+              system_component_id),
+          message_center::RichNotificationData(),
+          new message_center::HandleNotificationClickDelegate(click_callback),
+          gfx::kNoneIcon,
+          message_center::SystemNotificationWarningLevel::CRITICAL_WARNING);
+  notification->SetSystemPriority();
+  return notification;
+}
+
+std::unique_ptr<message_center::Notification> CreateSystemNotification(
+    message_center::NotificationType type,
+    const std::string& id,
+    const base::string16& title,
+    const base::string16& message,
+    const base::string16& display_source,
+    const GURL& origin_url,
+    const message_center::NotifierId& notifier_id,
+    const message_center::RichNotificationData& optional_fields,
+    scoped_refptr<message_center::NotificationDelegate> delegate,
+    const gfx::VectorIcon& small_image,
+    message_center::SystemNotificationWarningLevel color_type) {
+  DCHECK_EQ(message_center::NotifierType::SYSTEM_COMPONENT, notifier_id.type);
+  SkColor color = kSystemNotificationColorNormal;
+  switch (color_type) {
+    case message_center::SystemNotificationWarningLevel::NORMAL:
+      color = kSystemNotificationColorNormal;
+      break;
+    case message_center::SystemNotificationWarningLevel::WARNING:
+      color = kSystemNotificationColorWarning;
+      break;
+    case message_center::SystemNotificationWarningLevel::CRITICAL_WARNING:
+      color = kSystemNotificationColorCriticalWarning;
+      break;
+  }
+  auto notification = std::make_unique<message_center::Notification>(
+      type, id, title, message, gfx::Image(), display_source, origin_url,
+      notifier_id, optional_fields, delegate);
+  notification->set_accent_color(color);
+  if (!small_image.is_empty())
+    notification->set_vector_small_image(small_image);
+  return notification;
+}
+
+}  // namespace ash
diff --git a/ash/public/cpp/notification_utils.h b/ash/public/cpp/notification_utils.h
new file mode 100644
index 0000000..e78c085
--- /dev/null
+++ b/ash/public/cpp/notification_utils.h
@@ -0,0 +1,75 @@
+// 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_PUBLIC_CPP_NOTIFICATION_UTILS_H_
+#define ASH_PUBLIC_CPP_NOTIFICATION_UTILS_H_
+
+#include <string>
+
+#include "ash/public/cpp/ash_public_export.h"
+#include "base/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/strings/string16.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/message_center/public/cpp/notification.h"
+#include "ui/message_center/public/cpp/notification_types.h"
+#include "ui/message_center/public/cpp/notifier_id.h"
+
+class GURL;
+
+namespace gfx {
+struct VectorIcon;
+}
+
+namespace ui {
+namespace message_center {
+class NotificationDelegate;
+}
+}  // namespace ui
+
+namespace ash {
+
+// Accent colors of system notifications.
+constexpr SkColor kSystemNotificationColorNormal = gfx::kGoogleBlue700;
+constexpr SkColor kSystemNotificationColorWarning = gfx::kGoogleYellow900;
+constexpr SkColor kSystemNotificationColorCriticalWarning = gfx::kGoogleRed700;
+
+// Helper method to create a simple system notification. |click_callback|
+// will be invoked when the notification is clicked.
+//
+// It should only be used for critical notification, as SetSystemPriority and
+// CRITICAL_WARNING color are set inside, which means the notification would
+// not go away without user interaction.
+//
+// TODO(tetsui): Add a function parameter |small_image| of gfx::VectorIcon, so
+// display source of critical system notification is illustrated by icon.
+ASH_PUBLIC_EXPORT std::unique_ptr<message_center::Notification>
+CreateSystemNotification(const std::string& notification_id,
+                         const base::string16& title,
+                         const base::string16& message,
+                         const std::string& system_component_id,
+                         const base::RepeatingClosure& click_callback);
+
+// Factory method to create all kinds of notifications generated by system,
+// from normal priority ones to critical priority ones.
+// |small_image| is a small icon show on the upper left header to illustrate
+// |display_source| of the notification.
+// One specified in the |optional_fields| is overridden.
+ASH_PUBLIC_EXPORT std::unique_ptr<message_center::Notification>
+CreateSystemNotification(
+    message_center::NotificationType type,
+    const std::string& id,
+    const base::string16& title,
+    const base::string16& message,
+    const base::string16& display_source,
+    const GURL& origin_url,
+    const message_center::NotifierId& notifier_id,
+    const message_center::RichNotificationData& optional_fields,
+    scoped_refptr<message_center::NotificationDelegate> delegate,
+    const gfx::VectorIcon& small_image,
+    message_center::SystemNotificationWarningLevel color_type);
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_NOTIFICATION_UTILS_H_
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn
index 3a2b26ca..e86d917 100644
--- a/ash/public/interfaces/BUILD.gn
+++ b/ash/public/interfaces/BUILD.gn
@@ -10,6 +10,7 @@
 # enums and constants).
 mojom("interfaces_internal") {
   visibility = [ "//ash/public/cpp:*" ]
+  disable_variants = true
 
   sources = [
     "accelerator_controller.mojom",
@@ -72,6 +73,7 @@
     "//components/arc/common:notifications",
     "//components/sync/mojo:interfaces",
     "//mojo/public/mojom/base",
+    "//services/content/public/mojom",
     "//services/preferences/public/mojom",
     "//skia/public/interfaces",
     "//ui/accessibility:ax_enums_mojo",
@@ -95,6 +97,7 @@
 
 mojom("test_interfaces") {
   testonly = true
+  disable_variants = true
   sources = [
     "shelf_test_api.mojom",
     "shell_test_api.mojom",
diff --git a/ash/public/interfaces/app_list.mojom b/ash/public/interfaces/app_list.mojom
index 55e70bf..2838360 100644
--- a/ash/public/interfaces/app_list.mojom
+++ b/ash/public/interfaces/app_list.mojom
@@ -8,9 +8,11 @@
 import "components/sync/mojo/syncer.mojom";
 import "mojo/public/mojom/base/string16.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
+import "services/content/public/mojom/navigable_contents_factory.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/image/mojo/image.mojom";
 import "ui/gfx/range/mojo/range.mojom";
+import "url/mojom/url.mojom";
 
 // A structure holding the common information which is sent between ash and,
 // chrome representing an app list item.
@@ -59,17 +61,12 @@
   double display_score;       // A score to determine the result display order.
   bool is_omnibox_search;     // Whether this result is searched from Omnibox.
   bool is_installing;         // Whether this result is installing.
-  mojo_base.mojom.UnguessableToken? answer_card_contents_token;
-                              // A token used to render answer card, which is
-                              // empty before initialized. It's illegal to pass
-                              // an empty UnguessableToken across processes. So
-                              // we use a null value when it's empty here.
-  gfx.mojom.Size? answer_card_size;  // Preferred size of answer card. It is
-                                     // unset for non-answer-card results. For
-                                     // answer card results, it is set when
-                                     // the answer card WebContents finishes
-                                     // loading and its renderer notifies it
-                                     // about a new contents size.
+
+  url.mojom.Url? query_url;  // A query URL associated with this result. The
+                             // meaning and treatment of the URL
+                             // (e.g. displaying inline web contents) is
+                             // dependent on the result type.
+
   gfx.mojom.ImageSkia? icon;  // The icon of this result.
   gfx.mojom.ImageSkia? chip_icon;  // The icon of this result in a smaller
                                    // dimension to be rendered in suggestion
@@ -372,4 +369,9 @@
   StartVoiceInteractionSession();
   // Starts or stops voice interaction session based on current state.
   ToggleVoiceInteractionSession();
+
+  // Acquires a NavigableContentsFactory (indirectly) from the Content Service
+  // to allow the app list to display embedded web contents. Currently used only
+  // for answer card search results.
+  GetNavigableContentsFactory(content.mojom.NavigableContentsFactory& request);
 };
diff --git a/ash/public/interfaces/keyboard_controller.mojom b/ash/public/interfaces/keyboard_controller.mojom
index 505ada0..75f93cf 100644
--- a/ash/public/interfaces/keyboard_controller.mojom
+++ b/ash/public/interfaces/keyboard_controller.mojom
@@ -8,6 +8,15 @@
 import "ui/keyboard/public/keyboard_config.mojom";
 import "ui/keyboard/public/keyboard_enable_flag.mojom";
 
+enum HideReason {
+  // Hide requested by an explicit user action.
+  kUser,
+
+  // Hide requested due to a system event (e.g. because it would interfere with
+  // a menu or other on screen UI).
+  kSystem,
+};
+
 interface KeyboardControllerObserver {
   // Called when the keyboard is enabled or disabled. If ReloadKeyboard() is
   // called or other code enables the keyboard while already enabled, this will
@@ -44,8 +53,23 @@
   // changes, enables or disables the keyboard to match the new state.
   ClearEnableFlag(keyboard.mojom.KeyboardEnableFlag flag);
 
-  // Reloads the virtual keyboard if it is enabled.
-  ReloadKeyboard();
+  // Reloads the virtual keyboard if it is enabled and the URL has changed, e.g.
+  // the focus has switched from one type of field to another.
+  ReloadKeyboardIfNeeded();
+
+  // Rebuilds (disables and re-enables) the virtual keyboard if it is enabled.
+  // This is used to force a reload of the virtual keyboard when preferences or
+  // other configuration that affects loading the keyboard may have changed.
+  RebuildKeyboardIfEnabled();
+
+  // Returns whether the virtual keyboard is visible.
+  IsKeyboardVisible() => (bool visible);
+
+  // Shows the virtual keyboard on the current display if it is enabled.
+  ShowKeyboard();
+
+  // Hides the virtual keyboard if it is visible.
+  HideKeyboard(HideReason reason);
 
   // Adds a KeyboardControllerObserver.
   AddObserver(associated KeyboardControllerObserver observer);
diff --git a/ash/public/interfaces/system_tray_test_api.mojom b/ash/public/interfaces/system_tray_test_api.mojom
index fca24a4..1197370 100644
--- a/ash/public/interfaces/system_tray_test_api.mojom
+++ b/ash/public/interfaces/system_tray_test_api.mojom
@@ -9,7 +9,7 @@
 // Top-level items in the system tray bubble.
 // TODO(jamescook): Consolidate with SystemTrayItem::UmaType.
 enum TrayItem {
-  kEnterprise,
+  kAccessibility,
   kNetwork,
 };
 
@@ -36,7 +36,11 @@
   ShowDetailedView(TrayItem item) => ();
 
   // Returns true if the view exists in the bubble and is visible.
-  IsBubbleViewVisible(int32 view_id) => (bool visible);
+  // If |open_tray| is true, it also opens system tray bubble.
+  IsBubbleViewVisible(int32 view_id, bool open_tray) => (bool visible);
+
+  // Clicks the view |view_id|.
+  ClickBubbleView(int32 view_id) => ();
 
   // Returns the tooltip for a bubble view, or the empty string if the view
   // does not exist.
diff --git a/ash/public/interfaces/voice_interaction_controller.mojom b/ash/public/interfaces/voice_interaction_controller.mojom
index 6c1a9d2..e8b85ed 100644
--- a/ash/public/interfaces/voice_interaction_controller.mojom
+++ b/ash/public/interfaces/voice_interaction_controller.mojom
@@ -109,19 +109,6 @@
   // Called when the launch with mic open state is changed.
   NotifyLaunchWithMicOpen(bool launch_with_mic_open);
 
-  // Return if the voice interaction setting is enabled/disabled.
-  IsSettingEnabled() => (bool enabled);
-
-  // Return the voice interaction setup complete status.
-  IsSetupCompleted() => (bool completed);
-
-  // Return if the user has granted permission to access screen "context", the
-  // text and graphics content that is currently on screen.
-  IsContextEnabled() => (bool enabled);
-
-  // Return the voice interaction hotword listening status.
-  IsHotwordEnabled() => (bool enabled);
-
   // Add an observer.
   AddObserver(VoiceInteractionObserver observer);
 };
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 698a82e..1153f9f 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -36,7 +36,6 @@
 #include "ash/shell_state.h"
 #include "ash/system/status_area_layout_manager.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/tray_background_view.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/touch/touch_observer_hud.h"
@@ -364,13 +363,6 @@
   return shelf_widget ? shelf_widget->status_area_widget() : nullptr;
 }
 
-SystemTray* RootWindowController::GetSystemTray() {
-  // We assume in throughout the code that this will not return NULL. If code
-  // triggers this for valid reasons, it should test status_area_widget first.
-  CHECK(shelf_->shelf_widget()->status_area_widget());
-  return shelf_->shelf_widget()->status_area_widget()->system_tray();
-}
-
 bool RootWindowController::IsSystemTrayVisible() {
   TrayBackgroundView* tray = GetStatusAreaWidget()->unified_system_tray();
   return tray && tray->GetWidget()->IsVisible() && tray->visible();
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index 40b9741..6e9ede8 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -47,7 +47,6 @@
 class StackingController;
 class StatusAreaWidget;
 class SystemModalContainerLayoutManager;
-class SystemTray;
 class SystemWallpaperController;
 class TouchExplorationManager;
 class TouchObserverHUD;
@@ -140,11 +139,6 @@
   // May return null, for example for a secondary monitor at the login screen.
   StatusAreaWidget* GetStatusAreaWidget();
 
-  // Returns the system tray on this root window. Note that
-  // calling this on the root window that doesn't have a shelf will
-  // lead to a crash.
-  SystemTray* GetSystemTray();
-
   // Returns if system tray and its widget is visible.
   bool IsSystemTrayVisible();
 
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index b9befda..098b82c 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -827,17 +827,14 @@
   aura::Window* root_window = Shell::GetPrimaryRootWindow();
   ASSERT_EQ(root_window, controller->GetRootWindow());
 
-  aura::Window* contents_window = controller->GetKeyboardWindow();
-  contents_window->SetName("KeyboardWindow");
-  contents_window->SetBounds(
-      keyboard::KeyboardBoundsFromRootBounds(root_window->bounds(), 100));
-  contents_window->Show();
+  controller->ShowKeyboard(false /* locked */);
+  ASSERT_TRUE(keyboard::WaitUntilShown());
 
   ui::test::TestEventHandler handler;
   root_window->AddPreTargetHandler(&handler);
   ui::test::EventGenerator root_window_event_generator(root_window);
-  ui::test::EventGenerator keyboard_event_generator(root_window,
-                                                    contents_window);
+  ui::test::EventGenerator keyboard_event_generator(
+      root_window, controller->GetKeyboardWindow());
 
   views::Widget* modal_widget = CreateModalWidget(gfx::Rect(300, 10, 100, 100));
 
@@ -1064,11 +1061,8 @@
 
   auto* keyboard_controller = keyboard::KeyboardController::Get();
   keyboard_controller->ShowKeyboard(false);
-  keyboard_controller->NotifyKeyboardWindowLoaded();
-
+  ASSERT_TRUE(keyboard::WaitUntilShown());
   aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
-  keyboard_window->SetBounds(gfx::Rect(100, 100, 100, 100));
-  EXPECT_TRUE(keyboard_window->IsVisible());
   EXPECT_FALSE(keyboard_window->HasFocus());
 
   // Click on the keyboard. Make sure the keyboard receives the event, but does
diff --git a/ash/screen_util.cc b/ash/screen_util.cc
index 2b1d2a7..2507787 100644
--- a/ash/screen_util.cc
+++ b/ash/screen_util.cc
@@ -4,6 +4,10 @@
 
 #include "ash/screen_util.h"
 
+#include "ash/display/display_configuration_controller.h"
+#include "ash/display/mirror_window_controller.h"
+#include "ash/display/window_tree_host_manager.h"
+#include "ash/root_window_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "base/logging.h"
@@ -50,31 +54,21 @@
   if (!Shell::Get()->display_manager()->IsInUnifiedMode())
     return window->GetRootWindow()->bounds();
 
-  const display::DisplayManager* display_manager =
-      Shell::Get()->display_manager();
-  // Calculate the unified height scale value.
-  const int unified_logical_height = window->GetRootWindow()->bounds().height();
-  const auto& unified_display_info = display_manager->GetDisplayInfo(
-      display::Screen::GetScreen()->GetPrimaryDisplay().id());
-  const int unified_physical_height =
-      unified_display_info.bounds_in_native().height();
-  const float unified_height_scale =
-      static_cast<float>(unified_logical_height) / unified_physical_height;
+  // In Unified Mode, the display that should contain the shelf depends on the
+  // current shelf alignment.
+  const display::Display shelf_display =
+      Shell::Get()
+          ->display_configuration_controller()
+          ->GetPrimaryMirroringDisplayForUnifiedDesktop();
+  DCHECK_NE(shelf_display.id(), display::kInvalidDisplayId);
+  gfx::RectF shelf_display_screen_bounds(shelf_display.bounds());
 
-  // In unified desktop mode, there is only one shelf in the primary mirroing
-  // display which exists in the first row in the top left cell.
-  const int row_index = 0;
-  const int row_physical_height =
-      display_manager->GetUnifiedDesktopRowMaxHeight(row_index);
-  const int row_logical_height = row_physical_height * unified_height_scale;
+  // Transform the bounds back to the unified host's coordinates.
+  auto inverse_unified_transform =
+      window->GetRootWindow()->GetHost()->GetInverseRootTransform();
+  inverse_unified_transform.TransformRect(&shelf_display_screen_bounds);
 
-  const display::Display* first_display =
-      display_manager->GetPrimaryMirroringDisplayForUnifiedDesktop();
-  DCHECK(first_display);
-  gfx::SizeF size(first_display->size());
-  const float scale = row_logical_height / size.height();
-  size.Scale(scale, scale);
-  return gfx::Rect(gfx::ToCeiledSize(size));
+  return gfx::ToEnclosingRect(shelf_display_screen_bounds);
 }
 
 gfx::Rect SnapBoundsToDisplayEdge(const gfx::Rect& bounds,
diff --git a/ash/screen_util_unittest.cc b/ash/screen_util_unittest.cc
index f155bd1..1cbc09b 100644
--- a/ash/screen_util_unittest.cc
+++ b/ash/screen_util_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "ash/screen_util.h"
 
+#include "ash/root_window_controller.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
@@ -158,15 +160,41 @@
   display::Screen* screen = display::Screen::GetScreen();
   EXPECT_EQ(gfx::Size(766, 1254), screen->GetPrimaryDisplay().size());
 
-  // Regardless of where the window is, the shelf is always in the top left
-  // display in the matrix.
-  EXPECT_EQ(gfx::Rect(0, 0, 499, 400),
+  Shelf* shelf = Shell::GetPrimaryRootWindowController()->shelf();
+  EXPECT_EQ(shelf->alignment(), SHELF_ALIGNMENT_BOTTOM);
+
+  // Regardless of where the window is, the shelf with a bottom alignment is
+  // always in the bottom left display in the matrix.
+  EXPECT_EQ(gfx::Rect(0, 1057, 593, 198),
             screen_util::GetDisplayBoundsWithShelf(window));
 
   // Move to the bottom right display.
   widget->SetBounds(gfx::Rect(620, 940, 100, 100));
+  EXPECT_EQ(gfx::Rect(0, 1057, 593, 198),
+            screen_util::GetDisplayBoundsWithShelf(window));
+
+  // Change the shelf alignment to left, and expect that it now resides in the
+  // top left display in the matrix.
+  shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
   EXPECT_EQ(gfx::Rect(0, 0, 499, 400),
             screen_util::GetDisplayBoundsWithShelf(window));
+
+  // Change the shelf alignment to right, and expect that it now resides in the
+  // top right display in the matrix.
+  shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
+  EXPECT_EQ(gfx::Rect(499, 0, 267, 400),
+            screen_util::GetDisplayBoundsWithShelf(window));
+
+  // Change alignment back to bottom and change the unified display zoom factor.
+  // Expect that the display with shelf bounds will take into account the zoom
+  // factor.
+  shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+  display_manager()->UpdateZoomFactor(display::kUnifiedDisplayId, 3.f);
+  const display::Display unified_display =
+      display_manager()->GetDisplayForId(display::kUnifiedDisplayId);
+  EXPECT_FLOAT_EQ(unified_display.device_scale_factor(), 3.f);
+  EXPECT_EQ(gfx::Rect(0, 352, 198, 67),
+            screen_util::GetDisplayBoundsWithShelf(window));
 }
 
 TEST_F(ScreenUtilTest, SnapBoundsToDisplayEdge) {
diff --git a/ash/session/session_controller_unittest.cc b/ash/session/session_controller_unittest.cc
index 9acea02..489632c 100644
--- a/ash/session/session_controller_unittest.cc
+++ b/ash/session/session_controller_unittest.cc
@@ -14,7 +14,6 @@
 #include "ash/session/session_observer.h"
 #include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
-#include "ash/system/screen_security/screen_tray_item.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/overview/window_selector_controller.h"
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc
index 6995f6a..7ef526d 100644
--- a/ash/shelf/app_list_button.cc
+++ b/ash/shelf/app_list_button.cc
@@ -65,7 +65,7 @@
 AppListButton::AppListButton(InkDropButtonListener* listener,
                              ShelfView* shelf_view,
                              Shelf* shelf)
-    : views::ImageButton(nullptr),
+    : ShelfControlButton(),
       listener_(listener),
       shelf_view_(shelf_view),
       shelf_(shelf),
@@ -79,14 +79,10 @@
   mojom::VoiceInteractionObserverPtr ptr;
   voice_interaction_binding_.Bind(mojo::MakeRequest(&ptr));
   Shell::Get()->voice_interaction_controller()->AddObserver(std::move(ptr));
-  SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
-  set_ink_drop_base_color(kShelfInkDropBaseColor);
-  set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity);
   SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE));
-  SetSize(gfx::Size(kShelfControlSize, kShelfControlSize));
-  SetFocusPainter(TrayPopupUtils::CreateFocusPainter());
   set_notify_action(Button::NOTIFY_ON_PRESS);
+  set_has_ink_drop_action_on_click(false);
 
   // Initialize voice interaction overlay and sync the flags if active user
   // session has already started. This could happen when an external monitor
@@ -213,7 +209,7 @@
 
 std::unique_ptr<views::InkDropRipple> AppListButton::CreateInkDropRipple()
     const {
-  const int app_list_button_radius = ShelfConstants::app_list_button_radius();
+  const int app_list_button_radius = ShelfConstants::control_border_radius();
   gfx::Point center = GetCenterPoint();
   gfx::Rect bounds(center.x() - app_list_button_radius,
                    center.y() - app_list_button_radius,
@@ -247,7 +243,7 @@
 
 std::unique_ptr<views::InkDropMask> AppListButton::CreateInkDropMask() const {
   return std::make_unique<views::CircleInkDropMask>(
-      size(), GetCenterPoint(), ShelfConstants::app_list_button_radius());
+      size(), GetCenterPoint(), ShelfConstants::control_border_radius());
 }
 
 void AppListButton::PaintButtonContents(gfx::Canvas* canvas) {
@@ -272,9 +268,11 @@
     fg_flags.setColor(kShelfIconColor);
 
     if (UseVoiceInteractionStyle()) {
-      mojom::VoiceInteractionState state = Shell::Get()
-                                               ->voice_interaction_controller()
-                                               ->voice_interaction_state();
+      mojom::VoiceInteractionState state =
+          Shell::Get()
+              ->voice_interaction_controller()
+              ->voice_interaction_state()
+              .value_or(mojom::VoiceInteractionState::STOPPED);
       // active: 100% alpha, inactive: 54% alpha
       fg_flags.setAlpha(state == mojom::VoiceInteractionState::RUNNING
                             ? kVoiceInteractionRunningAlpha
@@ -297,27 +295,6 @@
   }
 }
 
-gfx::Point AppListButton::GetCenterPoint() const {
-  // For a bottom-aligned shelf, the button bounds could have a larger height
-  // than width (in the case of touch-dragging the shelf upwards) or a larger
-  // width than height (in the case of a shelf hide/show animation), so adjust
-  // the y-position of the circle's center to ensure correct layout. Similarly
-  // adjust the x-position for a left- or right-aligned shelf.
-  const int x_mid = width() / 2.f;
-  const int y_mid = height() / 2.f;
-
-  const ShelfAlignment alignment = shelf_->alignment();
-  if (alignment == SHELF_ALIGNMENT_BOTTOM ||
-      alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) {
-    return gfx::Point(x_mid, x_mid);
-  } else if (alignment == SHELF_ALIGNMENT_RIGHT) {
-    return gfx::Point(y_mid, y_mid);
-  } else {
-    DCHECK_EQ(alignment, SHELF_ALIGNMENT_LEFT);
-    return gfx::Point(width() - y_mid, y_mid);
-  }
-}
-
 void AppListButton::OnAppListVisibilityChanged(bool shown,
                                                aura::Window* root_window) {
   aura::Window* window = GetWidget() ? GetWidget()->GetNativeWindow() : nullptr;
@@ -393,12 +370,16 @@
   // voice interaction setup flow has completed.
   ShelfAlignment alignment = shelf_->alignment();
   mojom::VoiceInteractionState state =
-      Shell::Get()->voice_interaction_controller()->voice_interaction_state();
+      Shell::Get()
+          ->voice_interaction_controller()
+          ->voice_interaction_state()
+          .value_or(mojom::VoiceInteractionState::STOPPED);
   bool show_icon =
       (alignment == SHELF_ALIGNMENT_BOTTOM ||
        alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) &&
       state == mojom::VoiceInteractionState::STOPPED &&
-      Shell::Get()->voice_interaction_controller()->setup_completed() &&
+      Shell::Get()->voice_interaction_controller()->setup_completed().value_or(
+          false) &&
       chromeos::switches::IsVoiceInteractionEnabled();
   assistant_overlay_->StartAnimation(show_icon);
 }
@@ -406,8 +387,8 @@
 bool AppListButton::UseVoiceInteractionStyle() {
   VoiceInteractionController* controller =
       Shell::Get()->voice_interaction_controller();
-  bool settings_enabled = controller->settings_enabled();
-  bool setup_completed = controller->setup_completed();
+  bool settings_enabled = controller->settings_enabled().value_or(false);
+  bool setup_completed = controller->setup_completed().value_or(false);
   bool is_feature_allowed =
       controller->allowed_state() == mojom::AssistantAllowedState::ALLOWED;
   if (assistant_overlay_ && is_feature_allowed &&
diff --git a/ash/shelf/app_list_button.h b/ash/shelf/app_list_button.h
index 4990880..2b9df96f 100644
--- a/ash/shelf/app_list_button.h
+++ b/ash/shelf/app_list_button.h
@@ -11,6 +11,7 @@
 #include "ash/public/cpp/assistant/default_voice_interaction_observer.h"
 #include "ash/public/interfaces/voice_interaction_controller.mojom.h"
 #include "ash/session/session_observer.h"
+#include "ash/shelf/shelf_control_button.h"
 #include "ash/shell_observer.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -29,7 +30,7 @@
 class ShelfView;
 
 // Button used for the AppList icon on the shelf.
-class ASH_EXPORT AppListButton : public views::ImageButton,
+class ASH_EXPORT AppListButton : public ShelfControlButton,
                                  public ShellObserver,
                                  public SessionObserver,
                                  public DefaultVoiceInteractionObserver {
@@ -47,10 +48,6 @@
   // views::ImageButton:
   void OnGestureEvent(ui::GestureEvent* event) override;
 
-  // Get the center point of the app list button circle used to draw its
-  // background and ink drops.
-  gfx::Point GetCenterPoint() const;
-
  protected:
   // views::ImageButton:
   bool OnMousePressed(const ui::MouseEvent& event) override;
diff --git a/ash/shelf/app_list_button_unittest.cc b/ash/shelf/app_list_button_unittest.cc
index 0f97154..b0e35db 100644
--- a/ash/shelf/app_list_button_unittest.cc
+++ b/ash/shelf/app_list_button_unittest.cc
@@ -156,6 +156,8 @@
 
   // Enable voice interaction in system settings.
   Shell::Get()->voice_interaction_controller()->NotifySettingsEnabled(true);
+  Shell::Get()->voice_interaction_controller()->NotifyFeatureAllowed(
+      mojom::AssistantAllowedState::ALLOWED);
 
   ui::GestureEvent long_press =
       CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
@@ -198,6 +200,8 @@
   // interaction in settings.
   Shell::Get()->voice_interaction_controller()->NotifySettingsEnabled(false);
   Shell::Get()->voice_interaction_controller()->NotifySetupCompleted(true);
+  Shell::Get()->voice_interaction_controller()->NotifyFeatureAllowed(
+      mojom::AssistantAllowedState::ALLOWED);
 
   ui::GestureEvent long_press =
       CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
@@ -218,6 +222,8 @@
 
   // Disable voice interaction in system settings.
   Shell::Get()->voice_interaction_controller()->NotifySettingsEnabled(false);
+  Shell::Get()->voice_interaction_controller()->NotifyFeatureAllowed(
+      mojom::AssistantAllowedState::ALLOWED);
 
   ui::GestureEvent long_press =
       CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc
index 1c77f64..3298300 100644
--- a/ash/shelf/app_list_shelf_item_delegate.cc
+++ b/ash/shelf/app_list_shelf_item_delegate.cc
@@ -8,18 +8,8 @@
 #include <utility>
 
 #include "ash/app_list/app_list_controller_impl.h"
-#include "ash/app_list/home_launcher_gesture_handler.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
-#include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/shelf_model.h"
-#include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
-#include "ash/wm/mru_window_tracker.h"
-#include "ash/wm/overview/window_selector_controller.h"
-#include "ash/wm/splitview/split_view_controller.h"
-#include "ash/wm/tablet_mode/tablet_mode_controller.h"
-#include "ash/wm/window_state.h"
-#include "ui/display/manager/display_manager.h"
 
 namespace ash {
 
@@ -32,62 +22,8 @@
                                             int64_t display_id,
                                             ShelfLaunchSource source,
                                             ItemSelectedCallback callback) {
-  if (!Shell::Get()
-           ->app_list_controller()
-           ->IsHomeLauncherEnabledInTabletMode()) {
-    Shell::Get()->app_list_controller()->ToggleAppList(
-        display_id, app_list::kShelfButton, event->time_stamp());
-    std::move(callback).Run(SHELF_ACTION_APP_LIST_SHOWN, base::nullopt);
-    return;
-  }
-
-  // Whether the this action is handled.
-  bool handled = false;
-
-  HomeLauncherGestureHandler* home_launcher_gesture_handler =
-      Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
-  if (home_launcher_gesture_handler) {
-    handled = home_launcher_gesture_handler->ShowHomeLauncher(
-        Shell::Get()->display_manager()->GetDisplayForId(display_id));
-  }
-
-  if (!handled) {
-    if (Shell::Get()->window_selector_controller()->IsSelecting()) {
-      // End overview mode.
-      Shell::Get()->window_selector_controller()->ToggleOverview(
-          WindowSelector::EnterExitOverviewType::kWindowsMinimized);
-      handled = true;
-    }
-    if (Shell::Get()->split_view_controller()->IsSplitViewModeActive()) {
-      // End split view mode.
-      Shell::Get()->split_view_controller()->EndSplitView(
-          SplitViewController::EndReason::kHomeLauncherPressed);
-      handled = true;
-    }
-  }
-
-  if (!handled) {
-    // Minimize all windows that aren't the app list in reverse order to
-    // preserve the mru ordering.
-    aura::Window* app_list_container =
-        Shell::Get()->GetPrimaryRootWindow()->GetChildById(
-            kShellWindowId_AppListTabletModeContainer);
-    aura::Window::Windows windows =
-        Shell::Get()->mru_window_tracker()->BuildWindowForCycleList();
-    std::reverse(windows.begin(), windows.end());
-    for (auto* window : windows) {
-      if (!app_list_container->Contains(window) &&
-          !wm::GetWindowState(window)->IsMinimized()) {
-        wm::GetWindowState(window)->Minimize();
-        handled = true;
-      }
-    }
-  }
-
-  // Perform the "back" action for the app list.
-  if (!handled)
-    Shell::Get()->app_list_controller()->Back();
-
+  Shell::Get()->app_list_controller()->OnAppListButtonPressed(
+      display_id, app_list::kShelfButton, event->time_stamp());
   std::move(callback).Run(SHELF_ACTION_APP_LIST_SHOWN, base::nullopt);
 }
 
diff --git a/ash/shelf/back_button.cc b/ash/shelf/back_button.cc
index 5eff17e..ebf4ec9 100644
--- a/ash/shelf/back_button.cc
+++ b/ash/shelf/back_button.cc
@@ -27,27 +27,12 @@
 
 namespace ash {
 
-BackButton::BackButton() : views::ImageButton(nullptr) {
-  SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
-  set_has_ink_drop_action_on_click(true);
-  set_ink_drop_base_color(kShelfInkDropBaseColor);
-  set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity);
-
+BackButton::BackButton() : ShelfControlButton() {
   SetAccessibleName(l10n_util::GetStringUTF16(IDS_ASH_SHELF_BACK_BUTTON_TITLE));
-  SetSize(gfx::Size(kShelfControlSize, kShelfControlSize));
-  SetFocusPainter(TrayPopupUtils::CreateFocusPainter());
 }
 
 BackButton::~BackButton() = default;
 
-gfx::Point BackButton::GetCenterPoint() const {
-  // The button bounds could have a larger height than width (in the case of
-  // touch-dragging the shelf upwards) or a larger width than height (in the
-  // case of a shelf hide/show animation), so adjust the y-position of the
-  // button's center to ensure correct layout.
-  return gfx::Point(width() / 2.f, width() / 2.f);
-}
-
 void BackButton::OnGestureEvent(ui::GestureEvent* event) {
   ImageButton::OnGestureEvent(event);
   if (event->type() == ui::ET_GESTURE_TAP ||
@@ -67,27 +52,6 @@
   GenerateAndSendBackEvent(event.type());
 }
 
-std::unique_ptr<views::InkDropRipple> BackButton::CreateInkDropRipple() const {
-  return std::make_unique<views::FloodFillInkDropRipple>(
-      size(),
-      gfx::Insets(ShelfConstants::button_size() / 2 -
-                  ShelfConstants::app_list_button_radius()),
-      GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(),
-      ink_drop_visible_opacity());
-}
-
-std::unique_ptr<views::InkDrop> BackButton::CreateInkDrop() {
-  std::unique_ptr<views::InkDropImpl> ink_drop =
-      Button::CreateDefaultInkDropImpl();
-  ink_drop->SetShowHighlightOnHover(false);
-  return std::move(ink_drop);
-}
-
-std::unique_ptr<views::InkDropMask> BackButton::CreateInkDropMask() const {
-  return std::make_unique<views::CircleInkDropMask>(
-      size(), GetCenterPoint(), ShelfConstants::app_list_button_radius());
-}
-
 void BackButton::PaintButtonContents(gfx::Canvas* canvas) {
   // Use PaintButtonContents instead of SetImage so the icon gets drawn at
   // |GetCenterPoint| coordinates instead of always in the center.
diff --git a/ash/shelf/back_button.h b/ash/shelf/back_button.h
index 6301d33..a8869a7 100644
--- a/ash/shelf/back_button.h
+++ b/ash/shelf/back_button.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "ash/shelf/shelf_control_button.h"
 #include "base/macros.h"
 #include "ui/views/controls/button/image_button.h"
 
@@ -16,23 +17,16 @@
 // The back button shown on the shelf when tablet mode is enabled. Its opacity
 // and visiblity are handled by its parent, ShelfView, to ensure the fade
 // in/out of the icon matches the movement of ShelfView's items.
-class ASH_EXPORT BackButton : public views::ImageButton {
+class ASH_EXPORT BackButton : public ShelfControlButton {
  public:
   BackButton();
   ~BackButton() override;
 
-  // Get the center point of the back button used to draw its background and ink
-  // drops.
-  gfx::Point GetCenterPoint() const;
-
  protected:
   // views::ImageButton:
   void OnGestureEvent(ui::GestureEvent* event) override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
-  std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
-  std::unique_ptr<views::InkDrop> CreateInkDrop() override;
-  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
   void PaintButtonContents(gfx::Canvas* canvas) override;
 
  private:
diff --git a/ash/shelf/back_button_unittest.cc b/ash/shelf/back_button_unittest.cc
index a47851d..82faace 100644
--- a/ash/shelf/back_button_unittest.cc
+++ b/ash/shelf/back_button_unittest.cc
@@ -7,6 +7,8 @@
 #include <memory>
 
 #include "ash/accelerators/accelerator_controller.h"
+#include "ash/app_list/test/app_list_test_helper.h"
+#include "ash/app_list/views/app_list_view.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_view.h"
 #include "ash/shelf/shelf_view_test_api.h"
@@ -84,7 +86,15 @@
 
   AcceleratorController* controller = Shell::Get()->accelerator_controller();
 
-  // Register an accelerator that looks for back presses.
+  // Register an accelerator that looks for back presses. Note there is already
+  // an accelerator on AppListView, which will handle the accelerator since it
+  // is targeted before AcceleratorController (switching to tablet mode with no
+  // other windows activates the app list). First remove that accelerator. In
+  // release, there's only the AppList's accelerator, so it's always hit when
+  // the app list is active. (ash/accelerators.cc has VKEY_BROWSER_BACK, but it
+  // also needs Ctrl pressed).
+  GetAppListTestHelper()->GetAppListView()->ResetAccelerators();
+
   ui::Accelerator accelerator_back_press(ui::VKEY_BROWSER_BACK, ui::EF_NONE);
   accelerator_back_press.set_key_state(ui::Accelerator::KeyState::PRESSED);
   ui::TestAcceleratorTarget target_back_press;
diff --git a/ash/shelf/overflow_button.cc b/ash/shelf/overflow_button.cc
index 3059802..eb429e9 100644
--- a/ash/shelf/overflow_button.cc
+++ b/ash/shelf/overflow_button.cc
@@ -17,24 +17,15 @@
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/skbitmap_operations.h"
-#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
-#include "ui/views/animation/ink_drop_impl.h"
-#include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/layout/fill_layout.h"
 
 namespace ash {
 
 OverflowButton::OverflowButton(ShelfView* shelf_view, Shelf* shelf)
-    : Button(nullptr),
-      shelf_view_(shelf_view),
-      shelf_(shelf),
-      background_color_(kShelfDefaultBaseColor) {
+    : ShelfControlButton(), shelf_view_(shelf_view), shelf_(shelf) {
   DCHECK(shelf_view_);
 
-  SetInkDropMode(InkDropMode::ON);
-  set_ink_drop_base_color(kShelfInkDropBaseColor);
-  set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity);
   set_hide_ink_drop_when_showing_context_menu(false);
 
   SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
@@ -44,28 +35,11 @@
   horizontal_dots_image_view_->SetImage(
       gfx::CreateVectorIcon(kShelfOverflowHorizontalDotsIcon, kShelfIconColor));
   SetLayoutManager(std::make_unique<views::FillLayout>());
-  background_color_ = kShelfControlPermanentHighlightBackground;
   AddChildView(horizontal_dots_image_view_);
 }
 
 OverflowButton::~OverflowButton() = default;
 
-std::unique_ptr<views::InkDrop> OverflowButton::CreateInkDrop() {
-  std::unique_ptr<views::InkDropImpl> ink_drop =
-      CreateDefaultFloodFillInkDropImpl();
-  ink_drop->SetShowHighlightOnHover(false);
-  ink_drop->SetAutoHighlightMode(views::InkDropImpl::AutoHighlightMode::NONE);
-  return std::move(ink_drop);
-}
-
-std::unique_ptr<views::InkDropRipple> OverflowButton::CreateInkDropRipple()
-    const {
-  gfx::Insets insets = GetLocalBounds().InsetsFrom(CalculateButtonBounds());
-  return std::make_unique<views::FloodFillInkDropRipple>(
-      size(), insets, GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(),
-      ink_drop_visible_opacity());
-}
-
 bool OverflowButton::ShouldEnterPushedState(const ui::Event& event) {
   if (shelf_view_->IsShowingOverflowBubble())
     return false;
@@ -74,14 +48,7 @@
 }
 
 void OverflowButton::NotifyClick(const ui::Event& event) {
-  Button::NotifyClick(event);
-  shelf_view_->ButtonPressed(this, event, GetInkDrop());
-}
-
-std::unique_ptr<views::InkDropMask> OverflowButton::CreateInkDropMask() const {
-  gfx::Insets insets = GetLocalBounds().InsetsFrom(CalculateButtonBounds());
-  return std::make_unique<views::RoundRectInkDropMask>(
-      size(), insets, ShelfConstants::overflow_button_corner_radius());
+  shelf_view_->ButtonPressed(this, event, nullptr);
 }
 
 void OverflowButton::PaintButtonContents(gfx::Canvas* canvas) {
@@ -89,27 +56,17 @@
   PaintBackground(canvas, bounds);
 }
 
-void OverflowButton::PaintBackground(gfx::Canvas* canvas,
-                                     const gfx::Rect& bounds) {
-  cc::PaintFlags flags;
-  flags.setAntiAlias(true);
-  flags.setColor(background_color_);
-  canvas->DrawRoundRect(bounds, ShelfConstants::overflow_button_corner_radius(),
-                        flags);
-}
-
 gfx::Rect OverflowButton::CalculateButtonBounds() const {
-  const int overflow_button_size = ShelfConstants::overflow_button_size();
   ShelfAlignment alignment = shelf_->alignment();
   gfx::Rect content_bounds = GetContentsBounds();
   // Align the button to the top of a bottom-aligned shelf, to the right edge
   // a left-aligned shelf, and to the left edge of a right-aligned shelf.
-  const int inset = (ShelfConstants::shelf_size() - overflow_button_size) / 2;
+  const int inset = (ShelfConstants::shelf_size() - kShelfControlSize) / 2;
   const int x = alignment == SHELF_ALIGNMENT_LEFT
-                    ? content_bounds.right() - inset - overflow_button_size
+                    ? content_bounds.right() - inset - kShelfControlSize
                     : content_bounds.x() + inset;
-  return gfx::Rect(x, content_bounds.y() + inset, overflow_button_size,
-                   overflow_button_size);
+  return gfx::Rect(x, content_bounds.y() + inset, kShelfControlSize,
+                   kShelfControlSize);
 }
 
 }  // namespace ash
diff --git a/ash/shelf/overflow_button.h b/ash/shelf/overflow_button.h
index 14b4ec0..cc19b678 100644
--- a/ash/shelf/overflow_button.h
+++ b/ash/shelf/overflow_button.h
@@ -6,6 +6,7 @@
 #define ASH_SHELF_OVERFLOW_BUTTON_H_
 
 #include "ash/ash_export.h"
+#include "ash/shelf/shelf_control_button.h"
 #include "base/macros.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/image/image_skia.h"
@@ -21,7 +22,7 @@
 class ShelfView;
 
 // Shelf overflow button.
-class ASH_EXPORT OverflowButton : public views::Button {
+class ASH_EXPORT OverflowButton : public ShelfControlButton {
  public:
   // |shelf_view| is the view containing this button.
   OverflowButton(ShelfView* shelf_view, Shelf* shelf);
@@ -31,30 +32,19 @@
   friend class OverflowButtonTestApi;
 
   // views::Button:
-  std::unique_ptr<views::InkDrop> CreateInkDrop() override;
-  std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
   bool ShouldEnterPushedState(const ui::Event& event) override;
   void NotifyClick(const ui::Event& event) override;
-  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
   void PaintButtonContents(gfx::Canvas* canvas) override;
 
-  // Helper function to paint the background of the button at |bounds|.
-  void PaintBackground(gfx::Canvas* canvas, const gfx::Rect& bounds);
-
-  // Calculates the bounds of the overflow button based on the shelf alignment
-  // and overflow shelf visibility.
+  // Calculates the bounds of the control button based on the shelf alignment.
   gfx::Rect CalculateButtonBounds() const;
 
-  // The icon in the new UI: horizontal dots.
   const gfx::ImageSkia horizontal_dots_image_;
   views::ImageView* horizontal_dots_image_view_;
 
   ShelfView* shelf_view_;
   Shelf* shelf_;
 
-  // Color used to paint the background.
-  SkColor background_color_;
-
   DISALLOW_COPY_AND_ASSIGN(OverflowButton);
 };
 
diff --git a/ash/shelf/shelf_constants.h b/ash/shelf/shelf_constants.h
index cbc09e0..4da9753 100644
--- a/ash/shelf/shelf_constants.h
+++ b/ash/shelf/shelf_constants.h
@@ -69,7 +69,10 @@
 // The alpha value for the shelf background.
 ASH_EXPORT constexpr int kShelfTranslucentOverAppList = 51;            // 20%
 ASH_EXPORT constexpr int kShelfTranslucentAlpha = 153;                 // 60%
-ASH_EXPORT constexpr int kShelfTranslucentMaximizedWindow = 255;       // 100%
+// Using 0xFF causes clipping on the overlay candidate content, which prevent
+// HW overlay, probably due to a bug in compositor. Fix it and use 0xFF.
+// crbug.com/901538
+ASH_EXPORT constexpr int kShelfTranslucentMaximizedWindow = 254;       // ~100%
 
 // The alpha value used to darken a colorized shelf when the shelf is
 // translucent.
@@ -105,17 +108,6 @@
   // Size of the icons within shelf buttons.
   static int button_icon_size() { return kShelfButtonIconSize; }
 
-  // The width and height of the material design overflow button.
-  static int overflow_button_size() { return kShelfControlSize; }
-
-  // The radius of the rounded corners of the overflow button.
-  static int overflow_button_corner_radius() {
-    return overflow_button_size() / 2;
-  }
-
-  // The radius of the circular material design app list button.
-  static int app_list_button_radius() { return control_border_radius(); }
-
   // The radius of shelf control buttons.
   static int control_border_radius() { return kShelfControlSize / 2; }
 
diff --git a/ash/shelf/shelf_control_button.cc b/ash/shelf/shelf_control_button.cc
new file mode 100644
index 0000000..afeebba
--- /dev/null
+++ b/ash/shelf/shelf_control_button.cc
@@ -0,0 +1,67 @@
+// 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/shelf/shelf_control_button.h"
+
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_constants.h"
+#include "ash/system/tray/tray_popup_utils.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
+#include "ui/views/animation/ink_drop_impl.h"
+#include "ui/views/animation/ink_drop_mask.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+ShelfControlButton::ShelfControlButton() : views::ImageButton(nullptr) {
+  SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
+  set_has_ink_drop_action_on_click(true);
+  set_ink_drop_base_color(kShelfInkDropBaseColor);
+  set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity);
+
+  SetSize(gfx::Size(kShelfControlSize, kShelfControlSize));
+  SetFocusPainter(TrayPopupUtils::CreateFocusPainter());
+}
+
+ShelfControlButton::~ShelfControlButton() = default;
+
+gfx::Point ShelfControlButton::GetCenterPoint() const {
+  return gfx::Point(width() / 2.f, width() / 2.f);
+}
+
+std::unique_ptr<views::InkDropRipple> ShelfControlButton::CreateInkDropRipple()
+    const {
+  return std::make_unique<views::FloodFillInkDropRipple>(
+      size(),
+      gfx::Insets(ShelfConstants::button_size() / 2 -
+                  ShelfConstants::control_border_radius()),
+      GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(),
+      ink_drop_visible_opacity());
+}
+
+std::unique_ptr<views::InkDrop> ShelfControlButton::CreateInkDrop() {
+  std::unique_ptr<views::InkDropImpl> ink_drop =
+      Button::CreateDefaultInkDropImpl();
+  ink_drop->SetShowHighlightOnHover(false);
+  return std::move(ink_drop);
+}
+
+std::unique_ptr<views::InkDropMask> ShelfControlButton::CreateInkDropMask()
+    const {
+  return std::make_unique<views::CircleInkDropMask>(
+      size(), GetCenterPoint(), ShelfConstants::control_border_radius());
+}
+
+void ShelfControlButton::PaintBackground(gfx::Canvas* canvas,
+                                         const gfx::Rect& bounds) {
+  cc::PaintFlags flags;
+  flags.setAntiAlias(true);
+  flags.setColor(kShelfControlPermanentHighlightBackground);
+  canvas->DrawRoundRect(bounds, ShelfConstants::control_border_radius(), flags);
+}
+
+}  // namespace ash
diff --git a/ash/shelf/shelf_control_button.h b/ash/shelf/shelf_control_button.h
new file mode 100644
index 0000000..58f609f
--- /dev/null
+++ b/ash/shelf/shelf_control_button.h
@@ -0,0 +1,40 @@
+// 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_SHELF_SHELF_CONTROL_BUTTON_H_
+#define ASH_SHELF_SHELF_CONTROL_BUTTON_H_
+
+#include <memory>
+
+#include "ash/ash_export.h"
+#include "base/macros.h"
+#include "ui/views/controls/button/image_button.h"
+
+namespace ash {
+
+// Base class for controls shown on the shelf that are not app shortcuts, such
+// as the app list, back, and overflow buttons.
+class ASH_EXPORT ShelfControlButton : public views::ImageButton {
+ public:
+  ShelfControlButton();
+  ~ShelfControlButton() override;
+
+  // Get the center point of the button used to draw its background and ink
+  // drops.
+  gfx::Point GetCenterPoint() const;
+
+ protected:
+  // views::ImageButton:
+  std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
+  std::unique_ptr<views::InkDrop> CreateInkDrop() override;
+  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
+
+  void PaintBackground(gfx::Canvas* canvas, const gfx::Rect& bounds);
+
+  DISALLOW_COPY_AND_ASSIGN(ShelfControlButton);
+};
+
+}  // namespace ash
+
+#endif  // ASH_SHELF_SHELF_CONTROL_BUTTON_H_
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc
index af96c81..8e3e3e8 100644
--- a/ash/shelf/shelf_controller.cc
+++ b/ash/shelf/shelf_controller.cc
@@ -415,9 +415,9 @@
 
   // Skip this if the notification shouldn't badge an app.
   if (notification->notifier_id().type !=
-          message_center::NotifierId::APPLICATION &&
+          message_center::NotifierType::APPLICATION &&
       notification->notifier_id().type !=
-          message_center::NotifierId::ARC_APPLICATION) {
+          message_center::NotifierType::ARC_APPLICATION) {
     return;
   }
 
diff --git a/ash/shelf/shelf_controller_unittest.cc b/ash/shelf/shelf_controller_unittest.cc
index 9d965f5..819322b 100644
--- a/ash/shelf/shelf_controller_unittest.cc
+++ b/ash/shelf/shelf_controller_unittest.cc
@@ -42,7 +42,7 @@
                               const std::string& app_id,
                               const std::string& notification_id) {
   const message_center::NotifierId notifier_id(
-      message_center::NotifierId::APPLICATION, app_id);
+      message_center::NotifierType::APPLICATION, app_id);
   std::unique_ptr<message_center::Notification> notification =
       std::make_unique<message_center::Notification>(
           message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index ce9db3e2..7d5e072 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -487,12 +487,13 @@
   MaybeUpdateShelfBackground(AnimationChangeType::IMMEDIATE);
 }
 
-void ShelfLayoutManager::OnOverviewModeStarting() {
+void ShelfLayoutManager::OnOverviewModeStartingAnimationComplete(
+    bool canceled) {
   UpdateVisibilityState();
   MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE);
 }
 
-void ShelfLayoutManager::OnOverviewModeEnded() {
+void ShelfLayoutManager::OnOverviewModeEndingAnimationComplete(bool canceled) {
   UpdateVisibilityState();
   MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE);
 }
@@ -941,7 +942,8 @@
   gfx::Rect shelf_region = shelf_widget_->GetWindowBoundsInScreen();
   DCHECK(!display_.bounds().IsEmpty());
   shelf_region.Intersect(display_.bounds());
-  return shelf_region;
+  return screen_util::SnapBoundsToDisplayEdge(shelf_region,
+                                              shelf_widget_->GetNativeWindow());
 }
 
 gfx::Rect ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const {
@@ -960,7 +962,8 @@
 
   // TODO(pkotwicz): Figure out if we need any special handling when the
   // keyboard is visible.
-  return show_shelf_region_in_screen;
+  return screen_util::SnapBoundsToDisplayEdge(show_shelf_region_in_screen,
+                                              shelf_widget_->GetNativeWindow());
 }
 
 bool ShelfLayoutManager::HasVisibleWindow() const {
@@ -1316,7 +1319,7 @@
   HomeLauncherGestureHandler* home_launcher_handler =
       Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
   bool dragged_down;
-  if (home_launcher_handler && IsVisible() &&
+  if (home_launcher_handler &&
       home_launcher_handler->OnReleaseEvent(gesture_in_screen.location(),
                                             &dragged_down)) {
     if (dragged_down && visibility_state() == SHELF_AUTO_HIDE) {
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 327d873..3fdb91c 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -164,8 +164,8 @@
   void OnPinnedStateChanged(aura::Window* pinned_window) override;
   void OnAppListVisibilityChanged(bool shown,
                                   aura::Window* root_window) override;
-  void OnOverviewModeStarting() override;
-  void OnOverviewModeEnded() override;
+  void OnOverviewModeStartingAnimationComplete(bool canceled) override;
+  void OnOverviewModeEndingAnimationComplete(bool canceled) override;
   void OnSplitViewModeStarted() override;
   void OnSplitViewModeEnded() override;
 
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 55b08d8..9a6d801 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -27,9 +27,6 @@
 #include "ash/shell_test_api.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_test_helper.h"
-#include "ash/system/tray/system_tray.h"
-#include "ash/system/tray/system_tray_item.h"
-#include "ash/system/tray/test_system_tray_item.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wallpaper/wallpaper_controller.h"
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 5d1fb01..dae9315b 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -2051,6 +2051,12 @@
 void ShelfView::ShowContextMenuForView(views::View* source,
                                        const gfx::Point& point,
                                        ui::MenuSourceType source_type) {
+  // Prevent multiple requests for context menus before the current request
+  // completes. If a second request is sent before the first one can respond,
+  // the Chrome side ShelfItemDelegate will become unresponsive
+  // (https://crbug.com/881886).
+  if (waiting_for_context_menu_options_)
+    return;
   last_pressed_index_ = -1;
   const ShelfItem* item = ShelfItemForView(source);
   const int64_t display_id = GetDisplayIdForView(this);
@@ -2063,6 +2069,7 @@
     return;
   }
 
+  waiting_for_context_menu_options_ = true;
   // Get any custom entries; show the context menu in AfterGetContextMenuItems.
   model_->GetShelfItemDelegate(item->id)->GetContextMenuItems(
       display_id, base::Bind(&ShelfView::AfterGetContextMenuItems,
@@ -2076,6 +2083,7 @@
                          bool context_menu,
                          ui::MenuSourceType source_type) {
   DCHECK(!IsShowingMenu());
+  waiting_for_context_menu_options_ = false;
   if (menu_model->GetItemCount() == 0)
     return;
   menu_owner_ = source;
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index b9c0993..d08640c 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -534,6 +534,10 @@
   // True when an item being inserted or removed in the model cancels a drag.
   bool cancelling_drag_model_changed_ = false;
 
+  // Whether context menu options have been requested. Prevents multiple
+  // requests.
+  bool waiting_for_context_menu_options_ = false;
+
   // The timestamp of the event which closed the last menu - or 0.
   base::TimeTicks closing_event_time_;
 
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 2e20fe9..4220099 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -25,7 +25,6 @@
 #include "ash/shell.h"
 #include "ash/system/status_area_layout_manager.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
 #include "chromeos/chromeos_switches.h"
diff --git a/ash/shelf/shelf_widget_unittest.cc b/ash/shelf/shelf_widget_unittest.cc
index e6a1f9f..e58bd22 100644
--- a/ash/shelf/shelf_widget_unittest.cc
+++ b/ash/shelf/shelf_widget_unittest.cc
@@ -15,7 +15,6 @@
 #include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
 #include "ash/test_shell_delegate.h"
@@ -545,10 +544,15 @@
     AshTestBase::SetUp();
     ASSERT_TRUE(keyboard::IsKeyboardEnabled());
 
+    keyboard_controller()->LoadKeyboardWindowInBackground();
+    // Wait for the keyboard window to load.
+    base::RunLoop().RunUntilIdle();
+
     // These tests only apply to the floating virtual keyboard, as it is the
     // only case where both the virtual keyboard and the shelf are visible.
+    const gfx::Rect keyboard_bounds(0, 0, 1, 1);
     keyboard_controller()->SetContainerType(keyboard::ContainerType::FLOATING,
-                                            base::nullopt, base::DoNothing());
+                                            keyboard_bounds, base::DoNothing());
   }
 
   keyboard::KeyboardController* keyboard_controller() {
@@ -558,8 +562,7 @@
 
 TEST_F(ShelfWidgetVirtualKeyboardTest, ClickingHidesVirtualKeyboard) {
   keyboard_controller()->ShowKeyboard(false /* locked */);
-  keyboard_controller()->NotifyKeyboardWindowLoaded();
-  ASSERT_TRUE(keyboard_controller()->IsKeyboardVisible());
+  ASSERT_TRUE(keyboard::WaitUntilShown());
 
   ui::test::EventGenerator* generator = GetEventGenerator();
   generator->set_current_location(
@@ -572,8 +575,7 @@
 
 TEST_F(ShelfWidgetVirtualKeyboardTest, TappingHidesVirtualKeyboard) {
   keyboard_controller()->ShowKeyboard(false /* locked */);
-  keyboard_controller()->NotifyKeyboardWindowLoaded();
-  ASSERT_TRUE(keyboard_controller()->IsKeyboardVisible());
+  ASSERT_TRUE(keyboard::WaitUntilShown());
 
   ui::test::EventGenerator* generator = GetEventGenerator();
   generator->set_current_location(
@@ -586,8 +588,7 @@
 
 TEST_F(ShelfWidgetVirtualKeyboardTest, DoesNotHideLockedVirtualKeyboard) {
   keyboard_controller()->ShowKeyboard(true /* locked */);
-  keyboard_controller()->NotifyKeyboardWindowLoaded();
-  ASSERT_TRUE(keyboard_controller()->IsKeyboardVisible());
+  ASSERT_TRUE(keyboard::WaitUntilShown());
 
   ui::test::EventGenerator* generator = GetEventGenerator();
   generator->set_current_location(
diff --git a/ash/shell.cc b/ash/shell.cc
index db313f3..54d24ed 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -131,7 +131,6 @@
 #include "ash/wm/cursor_manager_chromeos.h"
 #include "ash/wm/event_client_impl.h"
 #include "ash/wm/immersive_context_ash.h"
-#include "ash/wm/immersive_handler_factory_ash.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/native_cursor_manager_ash.h"
@@ -511,10 +510,6 @@
   return !!GetPrimaryRootWindowController()->GetStatusAreaWidget();
 }
 
-SystemTray* Shell::GetPrimarySystemTray() {
-  return GetPrimaryRootWindowController()->GetSystemTray();
-}
-
 void Shell::SetLargeCursorSizeInDip(int large_cursor_size_in_dip) {
   window_tree_host_manager_->cursor_window_controller()
       ->SetLargeCursorSizeInDip(large_cursor_size_in_dip);
@@ -1025,8 +1020,6 @@
 
   wallpaper_controller_ = std::make_unique<WallpaperController>();
 
-  immersive_handler_factory_ = std::make_unique<ImmersiveHandlerFactoryAsh>();
-
   window_positioner_ = std::make_unique<WindowPositioner>();
 
   native_cursor_manager_ = new NativeCursorManagerAsh;
@@ -1097,8 +1090,7 @@
 
   // |app_list_controller_| is put after |tablet_mode_controller_| as the former
   // uses the latter in constructor.
-  app_list_controller_ = std::make_unique<AppListControllerImpl>(
-      window_service_owner_->window_service());
+  app_list_controller_ = std::make_unique<AppListControllerImpl>();
   shelf_controller_ = std::make_unique<ShelfController>();
 
   magnifier_key_scroll_handler_ = MagnifierKeyScroller::CreateHandler();
diff --git a/ash/shell.h b/ash/shell.h
index 871bb6e..f9854c3 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -125,7 +125,6 @@
 class ImeController;
 class ImeFocusHandler;
 class ImmersiveContext;
-class ImmersiveHandlerFactoryAsh;
 class KeyAccessibilityEnabler;
 class KeyboardBrightnessControlDelegate;
 class AshKeyboardController;
@@ -178,7 +177,6 @@
 class SystemGestureEventFilter;
 class SystemModalContainerEventFilter;
 class SystemNotificationController;
-class SystemTray;
 class SystemTrayModel;
 class SystemTrayNotifier;
 class TimeToFirstPresentRecorder;
@@ -565,9 +563,6 @@
   // Does the primary display have status area?
   bool HasPrimaryStatusArea();
 
-  // Returns the system tray on primary display.
-  SystemTray* GetPrimarySystemTray();
-
   // Starts the animation that occurs on first login.
   void DoInitialWorkspaceAnimation();
 
@@ -879,8 +874,6 @@
   // For testing only: simulate that a modal window is open
   bool simulate_modal_window_open_for_test_ = false;
 
-  std::unique_ptr<ImmersiveHandlerFactoryAsh> immersive_handler_factory_;
-
   std::unique_ptr<MessageCenterController> message_center_controller_;
 
   base::ObserverList<ShellObserver>::Unchecked shell_observers_;
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index 29d40cc..831adfb 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -329,9 +329,9 @@
     return true;
   }
 
-  ws::WindowService* GetWindowService() override {
+  void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) override {
     NOTIMPLEMENTED();
-    return nullptr;
   }
 
   std::unique_ptr<app_list::AppListModel> model_;
diff --git a/ash/shell/window_type_launcher.cc b/ash/shell/window_type_launcher.cc
index 95a2b54..14e7d0b2 100644
--- a/ash/shell/window_type_launcher.cc
+++ b/ash/shell/window_type_launcher.cc
@@ -289,8 +289,8 @@
             base::ASCIIToUTF16("Test Shell Web Notification"),
             base::ASCIIToUTF16("Notification message body."), gfx::Image(),
             base::ASCIIToUTF16("www.testshell.org"), GURL(),
-            message_center::NotifierId(message_center::NotifierId::APPLICATION,
-                                       "test-id"),
+            message_center::NotifierId(
+                message_center::NotifierType::APPLICATION, "test-id"),
             message_center::RichNotificationData(), nullptr /* delegate */);
 
     message_center::MessageCenter::Get()->AddNotification(
diff --git a/ash/strings/ash_strings_am.xtb b/ash/strings/ash_strings_am.xtb
index c63ef06..78aebb0a 100644
--- a/ash/strings/ash_strings_am.xtb
+++ b/ash/strings/ash_strings_am.xtb
@@ -188,7 +188,6 @@
 <translation id="4065525899979931964">{NUM_APPS,plural, =1{ቅናሽ ለአንድ መተግበሪያ}one{ቅናሽ ለ# መተግበሪያዎች}other{ቅናሽ ለ# መተግበሪያዎች}}</translation>
 <translation id="4072264167173457037">መካከለኛ ሲግናል</translation>
 <translation id="4146833061457621061">Play ሙዚቃ</translation>
-<translation id="4200057768455216496">የተተከለውን የማጉያ አቋራጭ ተጭነዋል። ሊያበሩት ይፈልጋሉ?</translation>
 <translation id="4217571870635786043">በቃል ማስጻፍ</translation>
 <translation id="4261870227682513959">የማሳወቂያ ቅንብሮችን አሳይ። ማሳወቂያዎች ጠፍተዋል</translation>
 <translation id="4269883910223712419">የዚህ መሣሪያ የሚከተሉትን የማድረግ ችሎታ አለው፦</translation>
@@ -259,6 +258,7 @@
 <translation id="5669267381087807207">በማግበር ላይ</translation>
 <translation id="5673434351075758678">ከ«<ph name="FROM_LOCALE" />» ወደ «<ph name="TO_LOCALE" />» የእርስዎን ቅንብሮች ከማመሳሰል በኋላ።</translation>
 <translation id="5691772641933328258">የጣት አሻራ አልታወቀም</translation>
+<translation id="5710450975648804523">አትረብሽ በርቷል</translation>
 <translation id="574392208103952083">መካከለኛ</translation>
 <translation id="5744083938413354016">መታ አድርጎ መጎተት</translation>
 <translation id="5750765938512549687">ብሉቱዝ ጠፍቷል</translation>
@@ -340,7 +340,6 @@
 <translation id="698231206551913481">አንዴ ይህ ተጠቃሚ ከተወገደ በኋላ ከዚህ ተጠቃሚ ጋር የተጎዳኙ ሁሉም ፋይሎች እና አካባቢያዊ ውሂብ በቋሚነት ይሰረዛሉ።</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" /> ላይ ተመልሰው ይምጡ።</translation>
 <translation id="7029814467594812963">ከክፍለ-ጊዜ ውጣ</translation>
-<translation id="7037152028959403492">የከፍተኛ ንጽጽር አቋራጩን ተጭነዋል። ሊያበሩት ይፈልጋሉ?</translation>
 <translation id="7066646422045619941">ይህ አውታረ መረብ በአስተዳዳሪዎ ነው የተሰናከለው።</translation>
 <translation id="7067196344162293536">በራስ-አሽከርክር</translation>
 <translation id="7068360136237591149">ፋይሎችን ይክፈቱ</translation>
@@ -377,7 +376,9 @@
 <translation id="7654687942625752712">የሚነገር ግብረመልስን ለማሰናከል ለአምስት ሰከንዶች ሁለቱንም የድምፅ ቁልፎች ተጭነው ያይዙ።</translation>
 <translation id="7692480393933218409">የተገናኙ የUSB-C መሣሪያዎችን ኃይል በመሙላት ላይ</translation>
 <translation id="7705524343798198388">ቪ ፒ ኤን</translation>
+<translation id="7723389094756330927">{NUM_NOTIFICATIONS,plural, =1{1 ማሳወቂያ}one{# ማሳወቂያዎች}other{# ማሳወቂያዎች}}</translation>
 <translation id="776344839111254542">የዝማኔ ዝርዝሮችን ለማየት ጠቅ ያድርጉ</translation>
+<translation id="7780159184141939021">ማያ ገጹን አሽከርክር</translation>
 <translation id="7796353162336583443">ማስታወሻ ለመያዝ፣ ቅጽበታዊ ገጽ እይታን ለማንሳት፣ Google ረዳቱን፣ ሌዘር ጠቋሚውን ወይም ማጉያ መነጽሩን ለመጠቀም በመደርደሪያው ላይ ያለውን የስታይለስ አዝራሩን መታ ያድርጉ።</translation>
 <translation id="7798302898096527229">ለመሰረዝ Search ወይም Shift ይጫኑ።</translation>
 <translation id="7814236020522506259"><ph name="HOUR" /> እና <ph name="MINUTE" /></translation>
@@ -406,7 +407,6 @@
 <translation id="8132793192354020517">ከ<ph name="NAME" /> ጋር ተገናኝቷል</translation>
 <translation id="813913629614996137">በማስጀመር ላይ…</translation>
 <translation id="8142699993796781067">የግል አውታረ መረብ</translation>
-<translation id="8152119955266188852">የሙሉ ማያ ገጽ ማጉያውን አቋራጭ ተጭነዋል። ሊያበሩት ይፈልጋሉ?</translation>
 <translation id="8190698733819146287">ቋንቋዎችን እና ግብአቶችን አብጅ...</translation>
 <translation id="8192202700944119416">ማሳወቂያዎች ተደብቀዋል</translation>
 <translation id="8236042855478648955">የዕረፍት ጊዜ</translation>
diff --git a/ash/strings/ash_strings_ar.xtb b/ash/strings/ash_strings_ar.xtb
index 71baa5e..7c88b97 100644
--- a/ash/strings/ash_strings_ar.xtb
+++ b/ash/strings/ash_strings_ar.xtb
@@ -188,7 +188,6 @@
 <translation id="4065525899979931964">{NUM_APPS,plural, =1{الإشعارات متوقفة لتطبيق واحد}zero{الإشعارات متوقفة لـ # تطبيق}two{الإشعارات متوقفة لتطبيقَين (#)}few{الإشعارات متوقفة لـ # تطبيقات}many{الإشعارات متوقفة لـ # تطبيقًا}other{الإشعارات متوقفة لـ # تطبيق}}</translation>
 <translation id="4072264167173457037">إشارة متوسطة</translation>
 <translation id="4146833061457621061">تشغيل الموسيقى</translation>
-<translation id="4200057768455216496">لقد ضغطت على اختصار المُكبِّر الذي تم إرساؤه. هل ترغب في تفعيله؟</translation>
 <translation id="4217571870635786043">إملاء</translation>
 <translation id="4261870227682513959">عرض إعدادات الإشعارات. تم إيقاف الإشعارات</translation>
 <translation id="4269883910223712419">يمتلك مشرف هذا الجهاز القدرة على ما يلي:</translation>
@@ -259,6 +258,7 @@
 <translation id="5669267381087807207">تفعيل</translation>
 <translation id="5673434351075758678">من "<ph name="FROM_LOCALE" />" إلى "<ph name="TO_LOCALE" />" بعد مزامنة الإعدادات.</translation>
 <translation id="5691772641933328258">لم يتمّ التعرُّف على البصمة</translation>
+<translation id="5710450975648804523">تمّ تفعيل وضع "عدم الإزعاج"</translation>
 <translation id="574392208103952083">متوسط</translation>
 <translation id="5744083938413354016">السحب بعد النقر</translation>
 <translation id="5750765938512549687">تم إيقاف البلوتوث</translation>
@@ -341,7 +341,6 @@
 <translation id="698231206551913481">سيتم حذف جميع الملفات والبيانات المحلية المرتبطة بهذا المستخدم نهائيًا بمجرد إزالة هذا المستخدم.</translation>
 <translation id="7015766095477679451">يمكنك العودة لاستخدام الجهاز في <ph name="COME_BACK_TIME" />.</translation>
 <translation id="7029814467594812963">إنهاء الجلسة</translation>
-<translation id="7037152028959403492">لقد ضغطت على اختصار التباين العالي. هل ترغب في تفعيله؟</translation>
 <translation id="7066646422045619941">تم إيقاف هذه الشبكة من قِبل مشرفك.</translation>
 <translation id="7067196344162293536">تدوير تلقائي</translation>
 <translation id="7068360136237591149">فتح الملفات</translation>
@@ -378,7 +377,9 @@
 <translation id="7654687942625752712">اضغط مع الاستمرار على مفتاحي مستوى الصوت لمدة خمس ثوانٍ لإيقاف التعليقات والملاحظات المنطوقة.</translation>
 <translation id="7692480393933218409">‏جارٍ شحن أجهزة USB-C المتصلة</translation>
 <translation id="7705524343798198388">VPN</translation>
+<translation id="7723389094756330927">{NUM_NOTIFICATIONS,plural, =1{إشعار واحد}zero{# إشعار}two{إشعاران (#)}few{# إشعارات}many{# إشعارًا}other{# إشعار}}</translation>
 <translation id="776344839111254542">النقر لعرض تفاصيل التحديث</translation>
+<translation id="7780159184141939021">تدوير الشاشة</translation>
 <translation id="7796353162336583443">‏انقر على زر قلم الشاشة على الرف لتدوين ملاحظة أو الحصول على لقطة شاشة أو استخدام مساعد Google أو مؤشر الليزر أو العدسة المكبرة.</translation>
 <translation id="7798302898096527229">‏اضغط على مفتاح البحث أو المفتاح Shift للإلغاء.</translation>
 <translation id="7814236020522506259"><ph name="HOUR" /> و<ph name="MINUTE" /></translation>
@@ -407,7 +408,6 @@
 <translation id="8132793192354020517">تم الاتصال بالموقع <ph name="NAME" /></translation>
 <translation id="813913629614996137">جارٍ التهيئة...</translation>
 <translation id="8142699993796781067">الشبكة الخاصة</translation>
-<translation id="8152119955266188852">لقد ضغطت على اختصار المُكبِّر بملء الشاشة. هل ترغب في تفعيله؟</translation>
 <translation id="8190698733819146287">تخصيص اللغات والإدخال...</translation>
 <translation id="8192202700944119416">يتم إخفاء الإشعارات.</translation>
 <translation id="8236042855478648955">حان وقت الراحة</translation>
diff --git a/ash/strings/ash_strings_bg.xtb b/ash/strings/ash_strings_bg.xtb
index 0ee13bd..c7ebaef 100644
--- a/ash/strings/ash_strings_bg.xtb
+++ b/ash/strings/ash_strings_bg.xtb
@@ -188,7 +188,6 @@
 <translation id="4065525899979931964">{NUM_APPS,plural, =1{Изключено за едно приложение}other{Изключено за # приложения}}</translation>
 <translation id="4072264167173457037">умерен сигнал</translation>
 <translation id="4146833061457621061">„Play music“ („Пусни музика“)</translation>
-<translation id="4200057768455216496">Използвахте клавишната комбинация за лупата в прикрепен режим. Искате ли да включите функцията?</translation>
 <translation id="4217571870635786043">Диктуване</translation>
 <translation id="4261870227682513959">Показване на настройките за известия. Известията са изключени</translation>
 <translation id="4269883910223712419">Администраторът на това устройство може:</translation>
@@ -259,6 +258,7 @@
 <translation id="5669267381087807207">Активира се</translation>
 <translation id="5673434351075758678">От <ph name="FROM_LOCALE" /> към <ph name="TO_LOCALE" /> след синхронизиране на настройките ви.</translation>
 <translation id="5691772641933328258">Отпечатъкът не бе разпознат</translation>
+<translation id="5710450975648804523">Режимът „Не безпокойте“ е включен</translation>
 <translation id="574392208103952083">Среден</translation>
 <translation id="5744083938413354016">Преместване чрез докосване</translation>
 <translation id="5750765938512549687">Функцията за Bluetooth е изключена</translation>
@@ -340,7 +340,6 @@
 <translation id="698231206551913481">След като този потребител бъде премахнат, всички свързани с него файлове и локални данни ще се изтрият за постоянно.</translation>
 <translation id="7015766095477679451">Ще бъда отново на ваше разположение в <ph name="COME_BACK_TIME" />.</translation>
 <translation id="7029814467594812963">Изход от сесията</translation>
-<translation id="7037152028959403492">Използвахте клавишната комбинация за режима на висок контраст. Искате ли да го включите?</translation>
 <translation id="7066646422045619941">Тази мрежа е деактивирана от администратора ви.</translation>
 <translation id="7067196344162293536">Автоматично завъртане</translation>
 <translation id="7068360136237591149">„Open files“ („Отвори файлове“)</translation>
@@ -377,7 +376,9 @@
 <translation id="7654687942625752712">Натиснете и двата бутона за силата на звука и ги задръжте за пет секунди, за да деактивирате обратната връзка с говор.</translation>
 <translation id="7692480393933218409">Свързаните устройства с USB-C се зареждат</translation>
 <translation id="7705524343798198388">VPN</translation>
+<translation id="7723389094756330927">{NUM_NOTIFICATIONS,plural, =1{1 известие}other{# известия}}</translation>
 <translation id="776344839111254542">Кликнете, за да видите подробности за актуализацията</translation>
+<translation id="7780159184141939021">Завъртане на екрана</translation>
 <translation id="7796353162336583443">Докоснете бутона с икона на писалка в лавицата, за да създадете бележка, да направите екранна снимка или да използвате Google Асистент, лазерната показалка или лупата.</translation>
 <translation id="7798302898096527229">Натиснете клавиша „търсене“ или Shift, за да анулирате.</translation>
 <translation id="7814236020522506259"><ph name="HOUR" /> и <ph name="MINUTE" /></translation>
@@ -406,7 +407,6 @@
 <translation id="8132793192354020517">Установена е връзка с/ъс <ph name="NAME" /></translation>
 <translation id="813913629614996137">Подготвя се за работа...</translation>
 <translation id="8142699993796781067">Частна мрежа</translation>
-<translation id="8152119955266188852">Използвахте клавишната комбинация за лупата за увеличаване на целия екран. Искате ли да включите функцията?</translation>
 <translation id="8190698733819146287">Персонализиране на езиците и въвеждането...</translation>
 <translation id="8192202700944119416">Известията са скрити.</translation>
 <translation id="8236042855478648955">Време е за почивка</translation>
diff --git a/ash/strings/ash_strings_bn.xtb b/ash/strings/ash_strings_bn.xtb
index 7b06bc1..fa9a8cc 100644
--- a/ash/strings/ash_strings_bn.xtb
+++ b/ash/strings/ash_strings_bn.xtb
@@ -188,7 +188,6 @@
 <translation id="4065525899979931964">{NUM_APPS,plural, =1{একটি অ্যাপের জন্য বন্ধ আছে}one{#টি অ্যাপের জন্য বন্ধ আছে}other{#টি অ্যাপের জন্য বন্ধ আছে}}</translation>
 <translation id="4072264167173457037">মাঝারি সিগন্যাল</translation>
 <translation id="4146833061457621061">মিউজিক চালান</translation>
-<translation id="4200057768455216496">ডক করা ম্যাগনিফায়ারের জন্য আপনি শর্টকাট প্রেস করেছেন। আপনি কি এটি চালু করতে চান?</translation>
 <translation id="4217571870635786043">ডিক্টেশন</translation>
 <translation id="4261870227682513959">বিজ্ঞপ্তি সেটিংস দেখান। বিজ্ঞপ্তি বন্ধ আছে</translation>
 <translation id="4269883910223712419">এই ডিভাইসের প্রশাসক এগুলি করতে পারেন:</translation>
@@ -259,6 +258,7 @@
 <translation id="5669267381087807207">সক্রিয় করা হচ্ছে</translation>
 <translation id="5673434351075758678">সেটিংস সিঙ্ক করার পরে "<ph name="FROM_LOCALE" />" থেকে "<ph name="TO_LOCALE" />" সেট করা হয়েছে।</translation>
 <translation id="5691772641933328258">আঙ্গুলের ছাপ শনাক্ত করা যায়নি</translation>
+<translation id="5710450975648804523">'বিরক্ত করবেন না' মোড চালু আছে</translation>
 <translation id="574392208103952083">মাঝারি</translation>
 <translation id="5744083938413354016">ট্যাপ করে টেনে আনা</translation>
 <translation id="5750765938512549687">ব্লুটুথ বন্ধ আছে</translation>
@@ -341,7 +341,6 @@
 <translation id="698231206551913481">একবার এই ব্যবহারকারীকে সরানো হলে এর সঙ্গে সংশ্লিষ্ট সমস্ত ফাইল এবং স্থানীয় ডেটা স্থায়ীভাবে মুছে ফেলা হবে।</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" />-এ আবার ব্যবহার করতে পারবেন।</translation>
 <translation id="7029814467594812963">সেশন থেকে প্রস্থান</translation>
-<translation id="7037152028959403492">উচ্চ কনট্রাস্টের জন্য আপনি শর্টকাট প্রেস করেছেন। আপনি কি এটি চালু করতে চান?</translation>
 <translation id="7066646422045619941">এই নেটওয়ার্কটি আপনার প্রশাসকের দ্বারা অক্ষম করা হয়েছে৷</translation>
 <translation id="7067196344162293536">স্বতঃ ঘূর্ণন</translation>
 <translation id="7068360136237591149">ফাইল খুলুন</translation>
@@ -378,7 +377,9 @@
 <translation id="7654687942625752712">পড়ে শোনানো বিকল্প চালু করতে পাঁচ সেকেন্ডের জন্য ভলিউম কীগুলি প্রেস করে ধরে রাখুন।</translation>
 <translation id="7692480393933218409">সংযুক্ত USB-C ডিভাইসগুলি চার্জ হচ্ছে</translation>
 <translation id="7705524343798198388">VPN</translation>
+<translation id="7723389094756330927">{NUM_NOTIFICATIONS,plural, =1{১টি বিজ্ঞপ্তি}one{#টি বিজ্ঞপ্তি}other{#টি বিজ্ঞপ্তি}}</translation>
 <translation id="776344839111254542">আপডেটের বিশদ বিবরণ জানার জন্য ক্লিক করুন</translation>
+<translation id="7780159184141939021">স্ক্রিন ঘোরান</translation>
 <translation id="7796353162336583443">একটি নোট, স্ক্রিনশট নিতে, Google সহায়ক, লেজার পয়ে