summaryrefslogtreecommitdiff
path: root/chromium/weblayer/browser
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-29 10:46:47 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-02 12:02:10 +0000
commit99677208ff3b216fdfec551fbe548da5520cd6fb (patch)
tree476a4865c10320249360e859d8fdd3e01833b03a /chromium/weblayer/browser
parentc30a6232df03e1efbd9f3b226777b07e087a1122 (diff)
downloadqtwebengine-chromium-99677208ff3b216fdfec551fbe548da5520cd6fb.tar.gz
BASELINE: Update Chromium to 86.0.4240.124
Change-Id: Ide0ff151e94cd665ae6521a446995d34a9d1d644 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/weblayer/browser')
-rw-r--r--chromium/weblayer/browser/DEPS14
-rw-r--r--chromium/weblayer/browser/OWNERS2
-rw-r--r--chromium/weblayer/browser/android/javatests/BUILD.gn15
-rwxr-xr-xchromium/weblayer/browser/android/javatests/skew/build_weblayer_instrumentation_test_cipd_pkg.py54
-rw-r--r--chromium/weblayer/browser/android/javatests/skew/expectations.txt27
-rw-r--r--chromium/weblayer/browser/android/javatests/skew/mb_config.pyl5
-rw-r--r--chromium/weblayer/browser/android/metrics/DEPS1
-rw-r--r--chromium/weblayer/browser/android/metrics/metrics_browsertest.cc208
-rw-r--r--chromium/weblayer/browser/android/metrics/metrics_test_helper.cc79
-rw-r--r--chromium/weblayer/browser/android/metrics/metrics_test_helper.h37
-rw-r--r--chromium/weblayer/browser/android/metrics/ukm_browsertest.cc (renamed from chromium/weblayer/browser/ukm_browsertest.cc)23
-rw-r--r--chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.cc7
-rw-r--r--chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.h2
-rw-r--r--chromium/weblayer/browser/android/resource_mapper.cc1
-rw-r--r--chromium/weblayer/browser/autofill_client_impl.cc9
-rw-r--r--chromium/weblayer/browser/autofill_client_impl.h5
-rw-r--r--chromium/weblayer/browser/browser_context_impl.cc15
-rw-r--r--chromium/weblayer/browser/browser_context_impl.h1
-rw-r--r--chromium/weblayer/browser/browser_controls_container_view.cc15
-rw-r--r--chromium/weblayer/browser/browser_controls_container_view.h14
-rw-r--r--chromium/weblayer/browser/browser_controls_navigation_state_handler.cc10
-rw-r--r--chromium/weblayer/browser/browser_controls_navigation_state_handler.h3
-rw-r--r--chromium/weblayer/browser/browser_impl.cc17
-rw-r--r--chromium/weblayer/browser/browser_impl.h8
-rw-r--r--chromium/weblayer/browser/browser_main_parts_impl.cc14
-rw-r--r--chromium/weblayer/browser/browser_process.cc7
-rw-r--r--chromium/weblayer/browser/browser_process.h2
-rw-r--r--chromium/weblayer/browser/browsing_data_remover_delegate.cc96
-rw-r--r--chromium/weblayer/browser/browsing_data_remover_delegate.h20
-rw-r--r--chromium/weblayer/browser/client_hints_browsertest.cc7
-rw-r--r--chromium/weblayer/browser/confirm_infobar_android.cc95
-rw-r--r--chromium/weblayer/browser/confirm_infobar_android.h40
-rw-r--r--chromium/weblayer/browser/content_browser_client_impl.cc133
-rw-r--r--chromium/weblayer/browser/content_browser_client_impl.h9
-rw-r--r--chromium/weblayer/browser/content_view_render_view.cc25
-rw-r--r--chromium/weblayer/browser/content_view_render_view.h4
-rw-r--r--chromium/weblayer/browser/controls_visibility_reason.h4
-rw-r--r--chromium/weblayer/browser/cookie_manager_impl.cc6
-rw-r--r--chromium/weblayer/browser/default_search_engine.cc35
-rw-r--r--chromium/weblayer/browser/default_search_engine.h35
-rw-r--r--chromium/weblayer/browser/download_browsertest.cc8
-rw-r--r--chromium/weblayer/browser/download_manager_delegate_impl.cc10
-rw-r--r--chromium/weblayer/browser/error_page_callback_proxy.cc16
-rw-r--r--chromium/weblayer/browser/error_page_callback_proxy.h2
-rw-r--r--chromium/weblayer/browser/errorpage_browsertest.cc110
-rw-r--r--chromium/weblayer/browser/favicon/favicon_backend_wrapper.cc193
-rw-r--r--chromium/weblayer/browser/favicon/favicon_backend_wrapper.h122
-rw-r--r--chromium/weblayer/browser/favicon/favicon_backend_wrapper_unittest.cc130
-rw-r--r--chromium/weblayer/browser/favicon/favicon_callback_proxy.cc45
-rw-r--r--chromium/weblayer/browser/favicon/favicon_callback_proxy.h39
-rw-r--r--chromium/weblayer/browser/favicon/favicon_fetcher_browsertest.cc167
-rw-r--r--chromium/weblayer/browser/favicon/favicon_fetcher_impl.cc27
-rw-r--r--chromium/weblayer/browser/favicon/favicon_fetcher_impl.h42
-rw-r--r--chromium/weblayer/browser/favicon/favicon_service_impl.cc249
-rw-r--r--chromium/weblayer/browser/favicon/favicon_service_impl.h105
-rw-r--r--chromium/weblayer/browser/favicon/favicon_service_impl_factory.cc50
-rw-r--r--chromium/weblayer/browser/favicon/favicon_service_impl_factory.h47
-rw-r--r--chromium/weblayer/browser/favicon/favicon_service_impl_observer.h21
-rw-r--r--chromium/weblayer/browser/favicon/favicon_tab_helper.cc124
-rw-r--r--chromium/weblayer/browser/favicon/favicon_tab_helper.h87
-rw-r--r--chromium/weblayer/browser/favicon/test_favicon_fetcher_delegate.cc46
-rw-r--r--chromium/weblayer/browser/favicon/test_favicon_fetcher_delegate.h55
-rw-r--r--chromium/weblayer/browser/file_select_helper.cc4
-rw-r--r--chromium/weblayer/browser/file_select_helper.h6
-rw-r--r--chromium/weblayer/browser/google_accounts_browsertest.cc229
-rw-r--r--chromium/weblayer/browser/google_accounts_callback_proxy.cc57
-rw-r--r--chromium/weblayer/browser/google_accounts_callback_proxy.h34
-rw-r--r--chromium/weblayer/browser/infobar_android.cc91
-rw-r--r--chromium/weblayer/browser/infobar_android.h86
-rw-r--r--chromium/weblayer/browser/infobar_container_android.cc15
-rw-r--r--chromium/weblayer/browser/infobar_container_android.h8
-rw-r--r--chromium/weblayer/browser/infobar_service.cc22
-rw-r--r--chromium/weblayer/browser/infobar_service.h8
-rw-r--r--chromium/weblayer/browser/insecure_form_controller_client.cc47
-rw-r--r--chromium/weblayer/browser/insecure_form_controller_client.h43
-rw-r--r--chromium/weblayer/browser/java/AndroidManifest.xml17
-rw-r--r--chromium/weblayer/browser/java/BUILD.gn95
-rw-r--r--chromium/weblayer/browser/java/DEPS10
-rw-r--r--chromium/weblayer/browser/java/ResourceId.template1
-rw-r--r--chromium/weblayer/browser/java/WebLayerBundleUtils.java.jinja29
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java358
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java71
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java82
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/ChildProcessServiceImpl.java6
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/ConfirmInfoBar.java81
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java121
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadCallbackProxy.java4
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadImpl.java4
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/ErrorPageCallbackProxy.java6
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java34
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/FaviconCallbackProxy.java64
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/FullscreenCallbackProxy.java28
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/FullscreenToast.java103
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/GoogleAccountsCallbackProxy.java77
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBar.java331
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarCompactLayout.java238
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainer.java23
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerLayout.java852
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java13
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarUiItem.java69
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarWrapper.java44
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java7
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaSessionManager.java18
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaStreamManager.java13
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java24
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java16
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/NewTabCallbackProxy.java2
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java28
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java16
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/SiteSettingsFragmentImpl.java62
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/SwipableOverlayView.java421
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java196
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java30
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateMenu.java75
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateMenuHelper.java321
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateOptions.java278
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateTabContent.java63
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateTabLayout.java240
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java55
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerFactoryImpl.java5
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java78
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationWrapperBuilder.java (renamed from chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationBuilder.java)17
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerSiteSettingsClient.java68
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerTabModalPresenter.java10
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/BrowsingDataType.java4
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/GoogleAccountServiceType.java19
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl3
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IErrorPageCallbackClient.aidl3
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IFaviconFetcher.aidl9
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IFaviconFetcherClient.aidl10
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IGoogleAccountsCallbackClient.aidl10
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl4
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationController.aidl7
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfile.aidl4
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl10
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IUrlBarController.aidl10
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl12
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/NavigateParams.java2
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py2
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/SettingType.java3
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl9
-rw-r--r--chromium/weblayer/browser/java/res/drawable/weblayer_infobar_wrapper_bg.xml16
-rw-r--r--chromium/weblayer/browser/java/res/layout/weblayer_infobar_translate_compact_content.xml2
-rw-r--r--chromium/weblayer/browser/java/res/layout/weblayer_infobar_translate_tab_content.xml28
-rw-r--r--chromium/weblayer/browser/java/res/layout/weblayer_translate_menu_item.xml21
-rw-r--r--chromium/weblayer/browser/java/res/layout/weblayer_translate_menu_item_checked.xml48
-rw-r--r--chromium/weblayer/browser/java/res/values/dimens.xml1
-rw-r--r--chromium/weblayer/browser/java/res/values/styles.xml12
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_af.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_am.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ar.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_as.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_az.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_be.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_bg.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_bn.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_bs.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ca.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_cs.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_da.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_de.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_el.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_en-GB.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_es-419.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_es.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_et.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_eu.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_fa.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_fi.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_fil.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_fr-CA.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_fr.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_gl.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_gu.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_hi.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_hr.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_hu.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_hy.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_id.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_is.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_it.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_iw.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ja.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ka.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_kk.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_km.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_kn.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ko.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ky.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_lo.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_lt.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_lv.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_mk.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ml.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_mn.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_mr.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ms.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_my.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ne.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_nl.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_no.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_or.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_pa.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_pl.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_pt-BR.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_pt-PT.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ro.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ru.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_si.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_sk.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_sl.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_sq.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_sr-Latn.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_sr.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_sv.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_sw.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ta.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_te.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_th.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_tr.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_uk.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_ur.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_uz.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_vi.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_zh-CN.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_zh-HK.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_zh-TW.xtb9
-rw-r--r--chromium/weblayer/browser/java/translations/weblayer_strings_zu.xtb9
-rw-r--r--chromium/weblayer/browser/java/weblayer_strings.grd28
-rw-r--r--chromium/weblayer/browser/navigation_browsertest.cc160
-rw-r--r--chromium/weblayer/browser/navigation_controller_impl.cc81
-rw-r--r--chromium/weblayer/browser/navigation_controller_impl.h26
-rw-r--r--chromium/weblayer/browser/navigation_error_navigation_throttle.cc73
-rw-r--r--chromium/weblayer/browser/navigation_error_navigation_throttle.h32
-rw-r--r--chromium/weblayer/browser/navigation_error_navigation_throttle_browsertest.cc94
-rw-r--r--chromium/weblayer/browser/navigation_impl.cc10
-rw-r--r--chromium/weblayer/browser/navigation_impl.h4
-rw-r--r--chromium/weblayer/browser/navigation_ui_data_impl.cc20
-rw-r--r--chromium/weblayer/browser/navigation_ui_data_impl.h34
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/no_state_prefetch_browsertest.cc212
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_link_manager_factory.cc51
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_link_manager_factory.h41
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.cc45
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.h37
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_manager_factory.cc42
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_manager_factory.h47
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.cc19
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.h33
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_tab_helper.cc37
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_tab_helper.h45
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_utils.cc27
-rw-r--r--chromium/weblayer/browser/no_state_prefetch/prerender_utils.h23
-rw-r--r--chromium/weblayer/browser/page_load_metrics_initialize.cc15
-rw-r--r--chromium/weblayer/browser/page_specific_content_settings_delegate.cc (renamed from chromium/weblayer/browser/tab_specific_content_settings_delegate.cc)55
-rw-r--r--chromium/weblayer/browser/page_specific_content_settings_delegate.h61
-rw-r--r--chromium/weblayer/browser/permissions/geolocation_permission_context_delegate.cc5
-rw-r--r--chromium/weblayer/browser/permissions/weblayer_permissions_client.cc27
-rw-r--r--chromium/weblayer/browser/permissions/weblayer_permissions_client.h9
-rw-r--r--chromium/weblayer/browser/persistence/browser_persister.cc6
-rw-r--r--chromium/weblayer/browser/persistence/browser_persister.h4
-rw-r--r--chromium/weblayer/browser/persistence/browser_persister_browsertest.cc46
-rw-r--r--chromium/weblayer/browser/persistence/browser_persister_file_utils.cc2
-rw-r--r--chromium/weblayer/browser/profile_browsertest.cc171
-rw-r--r--chromium/weblayer/browser/profile_disk_operations.cc12
-rw-r--r--chromium/weblayer/browser/profile_impl.cc107
-rw-r--r--chromium/weblayer/browser/profile_impl.h27
-rw-r--r--chromium/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.cc3
-rw-r--r--chromium/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc2
-rw-r--r--chromium/weblayer/browser/safe_browsing/safe_browsing_service.cc6
-rw-r--r--chromium/weblayer/browser/safe_browsing/safe_browsing_service.h8
-rw-r--r--chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.cc5
-rw-r--r--chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.h5
-rw-r--r--chromium/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc24
-rw-r--r--chromium/weblayer/browser/signin_url_loader_throttle.cc192
-rw-r--r--chromium/weblayer/browser/signin_url_loader_throttle.h61
-rw-r--r--chromium/weblayer/browser/ssl_browsertest.cc117
-rw-r--r--chromium/weblayer/browser/system_network_context_manager.h4
-rw-r--r--chromium/weblayer/browser/tab_impl.cc198
-rw-r--r--chromium/weblayer/browser/tab_impl.h52
-rw-r--r--chromium/weblayer/browser/tab_specific_content_settings_delegate.h54
-rw-r--r--chromium/weblayer/browser/translate_browsertest.cc39
-rw-r--r--chromium/weblayer/browser/translate_compact_infobar.cc59
-rw-r--r--chromium/weblayer/browser/translate_compact_infobar.h18
-rw-r--r--chromium/weblayer/browser/translate_utils.cc54
-rw-r--r--chromium/weblayer/browser/translate_utils.h43
-rw-r--r--chromium/weblayer/browser/tts_environment_android_impl.cc36
-rw-r--r--chromium/weblayer/browser/tts_environment_android_impl.h30
-rw-r--r--chromium/weblayer/browser/ukm_page_load_metrics_observer.cc41
-rw-r--r--chromium/weblayer/browser/ukm_page_load_metrics_observer.h35
-rw-r--r--chromium/weblayer/browser/url_bar/page_info_browsertest.cc4
-rw-r--r--chromium/weblayer/browser/url_bar/page_info_delegate_impl.cc17
-rw-r--r--chromium/weblayer/browser/url_bar/page_info_delegate_impl.h5
-rw-r--r--chromium/weblayer/browser/url_bar/url_bar_controller_impl.h3
-rw-r--r--chromium/weblayer/browser/weblayer_browser_interface_binders.cc32
-rw-r--r--chromium/weblayer/browser/weblayer_content_browser_overlay_manifest.cc19
-rw-r--r--chromium/weblayer/browser/weblayer_content_browser_overlay_manifest.h20
-rw-r--r--chromium/weblayer/browser/weblayer_impl_android.cc10
-rw-r--r--chromium/weblayer/browser/weblayer_security_blocking_page_factory.cc12
-rw-r--r--chromium/weblayer/browser/weblayer_variations_http_browsertest.cc52
299 files changed, 6940 insertions, 5290 deletions
diff --git a/chromium/weblayer/browser/DEPS b/chromium/weblayer/browser/DEPS
index d7477650b25..f1a963c03c5 100644
--- a/chromium/weblayer/browser/DEPS
+++ b/chromium/weblayer/browser/DEPS
@@ -7,6 +7,7 @@ include_rules = [
"+components/autofill/core/common",
"+components/base32",
"+components/blocked_content",
+ "+components/browsing_data/content",
"+components/browser_ui",
"+components/captive_portal",
"+components/cdm/browser",
@@ -18,7 +19,11 @@ include_rules = [
"+components/crash/core/common",
"+components/download/public/common",
"+components/embedder_support",
+ "+components/error_page/content/browser",
+ "+components/favicon_base",
+ "+components/favicon",
"+components/find_in_page",
+ "+components/infobars/android",
"+components/infobars/content",
"+components/infobars/core",
"+components/javascript_dialogs",
@@ -34,6 +39,8 @@ include_rules = [
"+components/permissions",
"+components/pref_registry",
"+components/prefs",
+ "+components/prerender/browser",
+ "+components/prerender/common",
"+components/resources/android",
"+components/safe_browsing/core",
"+components/safe_browsing/core/common",
@@ -42,11 +49,14 @@ include_rules = [
"+components/security_state/content/content_utils.h",
"+components/security_state/core/security_state.h",
"+components/sessions",
+ "+components/signin/core/browser",
+ "+components/signin/public",
"+components/site_isolation",
"+components/spellcheck/browser",
"+components/ssl_errors",
"+components/startup_metric_utils",
"+components/strings",
+ "+components/translate/content/android",
"+components/translate/content/browser",
"+components/translate/core/browser",
"+components/translate/core/common",
@@ -59,16 +69,18 @@ include_rules = [
"+components/web_cache/browser",
"+components/webrtc",
"+content/public",
+ "+google_apis",
"+mojo/public",
"+net",
"+sandbox",
- "+services/metrics/public/cpp/ukm_recorder.h",
+ "+services/metrics/public/cpp",
"+services/network/network_service.h",
"+services/network/public",
"+services/service_manager",
"+storage/browser/quota",
"+third_party/blink/public/common",
"+third_party/blink/public/mojom",
+ "+third_party/skia",
"+ui/aura",
"+ui/android",
"+ui/base",
diff --git a/chromium/weblayer/browser/OWNERS b/chromium/weblayer/browser/OWNERS
index f7104f63cd5..d9811aefda4 100644
--- a/chromium/weblayer/browser/OWNERS
+++ b/chromium/weblayer/browser/OWNERS
@@ -1,5 +1,3 @@
-per-file weblayer_content_browser_overlay_manifest.*=set noparent
-per-file weblayer_content_browser_overlay_manifest.*=file://ipc/SECURITY_OWNERS
per-file weblayer_browser_interface_binders.*=set noparent
per-file weblayer_browser_interface_binders.*=file://ipc/SECURITY_OWNERS
per-file content_browser_client_impl_receiver_bindings.*=set noparent
diff --git a/chromium/weblayer/browser/android/javatests/BUILD.gn b/chromium/weblayer/browser/android/javatests/BUILD.gn
index d069ae4c405..c8ed3bdcb5d 100644
--- a/chromium/weblayer/browser/android/javatests/BUILD.gn
+++ b/chromium/weblayer/browser/android/javatests/BUILD.gn
@@ -13,13 +13,17 @@ android_library("weblayer_java_tests") {
"src/org/chromium/weblayer/test/CookieManagerTest.java",
"src/org/chromium/weblayer/test/CrashReporterTest.java",
"src/org/chromium/weblayer/test/DataClearingTest.java",
+ "src/org/chromium/weblayer/test/DisplayCutoutTest.java",
"src/org/chromium/weblayer/test/DowngradeTest.java",
"src/org/chromium/weblayer/test/DownloadCallbackTest.java",
"src/org/chromium/weblayer/test/ErrorPageCallbackTest.java",
"src/org/chromium/weblayer/test/ExecuteScriptTest.java",
"src/org/chromium/weblayer/test/ExternalNavigationTest.java",
+ "src/org/chromium/weblayer/test/FaviconFetcherTest.java",
"src/org/chromium/weblayer/test/FindInPageTest.java",
"src/org/chromium/weblayer/test/FullscreenCallbackTest.java",
+ "src/org/chromium/weblayer/test/FullscreenSizeTest.java",
+ "src/org/chromium/weblayer/test/GoogleAccountsTest.java",
"src/org/chromium/weblayer/test/InputTypesTest.java",
"src/org/chromium/weblayer/test/NavigationTest.java",
"src/org/chromium/weblayer/test/NewTabCallbackTest.java",
@@ -31,7 +35,6 @@ android_library("weblayer_java_tests") {
"src/org/chromium/weblayer/test/TabCallbackTest.java",
"src/org/chromium/weblayer/test/TabListCallbackTest.java",
"src/org/chromium/weblayer/test/TabTest.java",
- "src/org/chromium/weblayer/test/TestFullscreenCallback.java",
"src/org/chromium/weblayer/test/TopControlsTest.java",
"src/org/chromium/weblayer/test/WebLayerLoadingTest.java",
"src/org/chromium/weblayer/test/WebLayerTest.java",
@@ -48,6 +51,7 @@ android_library("weblayer_java_tests") {
"//third_party/android_deps:android_support_v4_java",
"//third_party/android_deps:androidx_core_core_java",
"//third_party/android_deps:androidx_fragment_fragment_java",
+ "//third_party/android_deps:androidx_test_runner_java",
"//third_party/android_deps:espresso_java",
"//third_party/android_support_test_runner:rules_java",
"//third_party/android_support_test_runner:runner_java",
@@ -64,13 +68,17 @@ android_library("weblayer_private_java_tests") {
testonly = true
sources = [
"src/org/chromium/weblayer/test/BrowserControlsTest.java",
+ "src/org/chromium/weblayer/test/FullscreenCallbackPrivateTest.java",
"src/org/chromium/weblayer/test/GeolocationTest.java",
"src/org/chromium/weblayer/test/InfoBarTest.java",
"src/org/chromium/weblayer/test/MediaCaptureTest.java",
"src/org/chromium/weblayer/test/NetworkChangeNotifierTest.java",
+ "src/org/chromium/weblayer/test/PageInfoTest.java",
"src/org/chromium/weblayer/test/PopupTest.java",
"src/org/chromium/weblayer/test/ResourceLoadingTest.java",
+ "src/org/chromium/weblayer/test/TabPrivateTest.java",
"src/org/chromium/weblayer/test/TranslateTest.java",
+ "src/org/chromium/weblayer/test/UrlBarControllerTest.java",
]
deps = [
":weblayer_java_private_test_support",
@@ -81,6 +89,9 @@ android_library("weblayer_private_java_tests") {
"//net/android:net_java_test_support",
"//third_party/android_deps:android_support_v4_java",
"//third_party/android_deps:androidx_fragment_fragment_java",
+ "//third_party/android_deps:androidx_test_runner_java",
+ "//third_party/android_deps:espresso_java",
+ "//third_party/android_sdk:android_test_base_java",
"//third_party/android_support_test_runner:rules_java",
"//third_party/android_support_test_runner:runner_java",
"//third_party/hamcrest:hamcrest_java",
@@ -103,6 +114,7 @@ android_library("weblayer_java_test_support") {
"src/org/chromium/weblayer/test/NewTabCallbackImpl.java",
"src/org/chromium/weblayer/test/ResourceUtil.java",
"src/org/chromium/weblayer/test/SiteSettingsActivityTestRule.java",
+ "src/org/chromium/weblayer/test/TestFullscreenCallback.java",
"src/org/chromium/weblayer/test/WebLayerActivityTestRule.java",
"src/org/chromium/weblayer/test/WebLayerJUnit4ClassRunner.java",
]
@@ -229,6 +241,7 @@ android_test_apk("weblayer_bundle_test_apk") {
"//base:base_java",
"//base:base_java_test_support",
"//content/public/test/android:content_java_test_support",
+ "//third_party/android_deps:androidx_test_runner_java",
"//third_party/android_support_test_runner:rules_java",
"//third_party/android_support_test_runner:runner_java",
"//third_party/junit:junit",
diff --git a/chromium/weblayer/browser/android/javatests/skew/build_weblayer_instrumentation_test_cipd_pkg.py b/chromium/weblayer/browser/android/javatests/skew/build_weblayer_instrumentation_test_cipd_pkg.py
index 612977d6020..0868a5d57fe 100755
--- a/chromium/weblayer/browser/android/javatests/skew/build_weblayer_instrumentation_test_cipd_pkg.py
+++ b/chromium/weblayer/browser/android/javatests/skew/build_weblayer_instrumentation_test_cipd_pkg.py
@@ -14,25 +14,52 @@
# skew test will pick up the new package in successive runs.
import argparse
+import contextlib
import os
import shutil
import subprocess
import sys
+import re
import tempfile
import zipfile
+SRC_DIR = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..')
# Run mb.py out of the current branch for simplicity.
-MB_PATH = './tools/mb/mb.py'
+MB_PATH = os.path.join('tools', 'mb', 'mb.py')
# Get the config specifying the gn args from the location of this script.
MB_CONFIG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)),
'mb_config.pyl')
+CHROMIUM_VERSION_REGEX = r'\d+\.\d+\.\d+\.\d+$'
+
# CIPD package path.
# https://chrome-infra-packages.appspot.com/p/chromium/testing/weblayer-x86/+/
CIPD_PKG_PATH='chromium/testing/weblayer-x86'
+
+@contextlib.contextmanager
+def temporarily_chdir_to_src(local_paths=None):
+ """Change directories to chromium/src when entering with block and
+ then change back to current directory after exiting with block.
+
+ Args:
+ local_paths: List of paths to change into relative paths.
+
+ Returns:
+ List of paths relative to chromium/src.
+ """
+ curr_dir = os.getcwd()
+ paths_rel_to_src = [
+ os.path.relpath(p, SRC_DIR) for p in local_paths or []]
+ try:
+ os.chdir(SRC_DIR)
+ yield paths_rel_to_src
+ finally:
+ os.chdir(curr_dir)
+
+
def zip_test_target(zip_filename):
"""Create zip of all deps for weblayer_instrumentation_test_apk.
@@ -44,7 +71,7 @@ def zip_test_target(zip_filename):
'--master=dummy.master',
'--builder=dummy.builder',
'--config-file=%s' % MB_CONFIG_PATH,
- 'out/Release',
+ os.path.join('out', 'Release'),
'weblayer_instrumentation_test_apk',
zip_filename]
print(' '.join(cmd))
@@ -68,6 +95,16 @@ def build_cipd_pkg(input_path, cipd_filename):
subprocess.check_call(cmd)
+def get_chromium_version():
+ with open(os.path.join(SRC_DIR, 'chrome', 'VERSION')) as f:
+ version = '.'.join(line[line.index('=') + 1:]
+ for line in f.read().splitlines())
+ if not re.match(CHROMIUM_VERSION_REGEX, version):
+ raise ValueError("Chromium version, '%s', is not in proper format" %
+ version)
+ return version
+
+
def main():
parser = argparse.ArgumentParser(
description='Package weblayer instrumentation tests for CIPD.')
@@ -75,9 +112,11 @@ def main():
'--cipd_out',
required=True,
help="Output filename for resulting .cipd file.")
- args = parser.parse_args()
- with tempfile.TemporaryDirectory() as tmp_dir:
+ args = parser.parse_args()
+ chromium_version = get_chromium_version()
+ with tempfile.TemporaryDirectory() as tmp_dir, \
+ temporarily_chdir_to_src([args.cipd_out]) as cipd_out_src_rel_paths:
# Create zip archive of test target.
zip_filename = os.path.join(tmp_dir, 'file.zip')
zip_test_target(zip_filename)
@@ -91,10 +130,11 @@ def main():
# Create CIPD archive.
tmp_cipd_filename = os.path.join(tmp_dir, 'file.cipd')
build_cipd_pkg(extracted, tmp_cipd_filename)
- shutil.move(tmp_cipd_filename, args.cipd_out)
+ shutil.move(tmp_cipd_filename, cipd_out_src_rel_paths[0])
- print(('Use "cipd pkg-register %s -verbose -tag \'version:<branch>\'" ' +
- 'to upload package to the cipd server.') % args.cipd_out)
+ print(('Use "cipd pkg-register %s -verbose -tag \'version:%s\'" ' +
+ 'to upload package to the cipd server.') %
+ (args.cipd_out, chromium_version))
print('Use "cipd set-ref chromium/testing/weblayer-x86 --version ' +
'<CIPD instance version> -ref m<milestone>" to update the ref.')
print('The CIPD instance version can be found on the "Instance" line ' +
diff --git a/chromium/weblayer/browser/android/javatests/skew/expectations.txt b/chromium/weblayer/browser/android/javatests/skew/expectations.txt
index 365f067e95e..cdd7c2a0758 100644
--- a/chromium/weblayer/browser/android/javatests/skew/expectations.txt
+++ b/chromium/weblayer/browser/android/javatests/skew/expectations.txt
@@ -22,25 +22,26 @@
[ impl_lte_83 ] org.chromium.weblayer.test.TabTest#testBeforeUnloadNoHandler [ Skip ]
[ impl_lte_83 ] org.chromium.weblayer.test.TabTest#testBeforeUnloadNoInteraction [ Skip ]
-# Replace was removed in https://crrev.com/c/2150968, see https://crbug.com/1070851.
-[ impl_lte_83 ] org.chromium.weblayer.test.NavigationTest#testReplace [ Skip ]
+# Replace was removed in https://crrev.com/c/2150968.
+crbug.com/1070851 [ impl_lte_83 ] org.chromium.weblayer.test.NavigationTest#testReplace [ Skip ]
-# Fixed in https://crrev.com/c/2180022, see https://crbug.com/1077243.
-[ impl_lte_83 ] org.chromium.weblayer.test.FullscreenCallbackTest#testExitFullscreenWhenTabDestroyed [ Skip ]
+# Fixed in https://crrev.com/c/2180022.
+crbug.com/1077243 [ impl_lte_83 ] org.chromium.weblayer.test.FullscreenCallbackTest#testExitFullscreenWhenTabDestroyed [ Skip ]
-# https://crbug.com/1079491.
-[ impl_lte_83 ] org.chromium.weblayer.test.NavigationTest#testSetUserAgentString [ Skip ]
+crbug.com/1096570 [ impl_lte_83 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectLaunched [ Skip ]
# -------------------------------------
# Tests against older WebLayer clients.
# -------------------------------------
-# Intentionally changed in M84, https://crrev.com/c/2130790. See https://crbug.com/1078973.
-[ client_lte_83 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentLaunchedViaOnLoad [ Skip ]
-[ client_lte_83 ] org.chromium.weblayer.test.ExternalNavigationTest#testNonHandledExternalIntentWithFallbackUrlThatLaunchesIntentAfterRedirectLaunchesFallbackIntent [ Skip ]
+# Intentionally changed in M84, https://crrev.com/c/2130790.
+crbug.com/1078973 [ client_lte_83 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentLaunchedViaOnLoad [ Skip ]
+crbug.com/1078973 [ client_lte_83 ] org.chromium.weblayer.test.ExternalNavigationTest#testNonHandledExternalIntentWithFallbackUrlThatLaunchesIntentAfterRedirectLaunchesFallbackIntent [ Skip ]
-# Replace was removed in https://crrev.com/c/2150968, see https://crbug.com/1070851.
-[ client_lte_83 ] org.chromium.weblayer.test.NavigationTest#testReplace [ Skip ]
+# Replace was removed in https://crrev.com/c/2150968.
+crbug.com/1070851 [ client_lte_83 ] org.chromium.weblayer.test.NavigationTest#testReplace [ Skip ]
-# Test was made private, https://crbug.com/1087451.
-[ client_lte_84 ] org.chromium.weblayer.test.TopControlsTest#testBasic [ Skip ]
+# Test was made private.
+crbug.com/1087451 [ client_lte_84 ] org.chromium.weblayer.test.TopControlsTest#testBasic [ Skip ]
+
+crbug.com/1096570 [ client_lte_83 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectBlocked [ Skip ]
diff --git a/chromium/weblayer/browser/android/javatests/skew/mb_config.pyl b/chromium/weblayer/browser/android/javatests/skew/mb_config.pyl
index 726ef6f3fc6..8e4311f0432 100644
--- a/chromium/weblayer/browser/android/javatests/skew/mb_config.pyl
+++ b/chromium/weblayer/browser/android/javatests/skew/mb_config.pyl
@@ -65,9 +65,10 @@
'release': {
'gn_args': 'is_debug=false',
},
-
+ # TODO(rmhasan): Add back GOMA support when you can start the goma proxy
+ # in a recipe.
'release_bot': {
- 'mixins': ['release', 'static', 'goma'],
+ 'mixins': ['release', 'static'],
},
'static': {
diff --git a/chromium/weblayer/browser/android/metrics/DEPS b/chromium/weblayer/browser/android/metrics/DEPS
index 44a37a03920..3a3f231d4d2 100644
--- a/chromium/weblayer/browser/android/metrics/DEPS
+++ b/chromium/weblayer/browser/android/metrics/DEPS
@@ -1,4 +1,5 @@
include_rules = [
"+components/metrics",
"+google_apis/google_api_keys.h",
+ "+third_party/metrics_proto"
]
diff --git a/chromium/weblayer/browser/android/metrics/metrics_browsertest.cc b/chromium/weblayer/browser/android/metrics/metrics_browsertest.cc
new file mode 100644
index 00000000000..ec8bff6d7a6
--- /dev/null
+++ b/chromium/weblayer/browser/android/metrics/metrics_browsertest.cc
@@ -0,0 +1,208 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <deque>
+
+#include "base/command_line.h"
+#include "base/metrics/metrics_hashes.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/no_destructor.h"
+#include "base/test/bind_test_util.h"
+#include "components/metrics/log_decoder.h"
+#include "components/metrics/metrics_log_uploader.h"
+#include "components/metrics/metrics_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
+#include "weblayer/browser/android/metrics/metrics_test_helper.h"
+#include "weblayer/browser/android/metrics/weblayer_metrics_service_client.h"
+#include "weblayer/browser/profile_impl.h"
+#include "weblayer/public/navigation_controller.h"
+#include "weblayer/public/profile.h"
+#include "weblayer/public/tab.h"
+#include "weblayer/shell/browser/shell.h"
+#include "weblayer/test/weblayer_browser_test.h"
+#include "weblayer/test/weblayer_browser_test_utils.h"
+
+namespace weblayer {
+
+namespace {
+
+bool HasHistogramWithHash(const metrics::ChromeUserMetricsExtension& uma_log,
+ uint64_t hash) {
+ for (int i = 0; i < uma_log.histogram_event_size(); ++i) {
+ if (uma_log.histogram_event(i).name_hash() == hash) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+class MetricsBrowserTest : public WebLayerBrowserTest {
+ public:
+ void SetUp() override {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitch(metrics::switches::kForceEnableMetricsReporting);
+
+ InstallTestGmsBridge(HasUserConsent(),
+ base::BindRepeating(&MetricsBrowserTest::OnLogMetrics,
+ base::Unretained(this)));
+ WebLayerMetricsServiceClient::GetInstance()->SetFastStartupForTesting(true);
+ WebLayerMetricsServiceClient::GetInstance()->SetUploadIntervalForTesting(
+ base::TimeDelta::FromMilliseconds(10));
+ WebLayerBrowserTest::SetUp();
+ }
+
+ void TearDown() override {
+ RemoveTestGmsBridge();
+ WebLayerBrowserTest::TearDown();
+ }
+
+ void OnLogMetrics(metrics::ChromeUserMetricsExtension metric) {
+ metrics_logs_.push_back(metric);
+ if (on_new_log_)
+ std::move(on_new_log_).Run();
+ }
+
+ metrics::ChromeUserMetricsExtension WaitForNextMetricsLog() {
+ if (metrics_logs_.empty()) {
+ base::RunLoop run_loop;
+ on_new_log_ = run_loop.QuitClosure();
+ run_loop.Run();
+ DCHECK(!metrics_logs_.empty());
+ }
+ metrics::ChromeUserMetricsExtension tmp = std::move(metrics_logs_.front());
+ metrics_logs_.pop_front();
+ return tmp;
+ }
+
+ size_t GetNumLogs() const { return metrics_logs_.size(); }
+
+ virtual bool HasUserConsent() { return true; }
+
+ private:
+ std::unique_ptr<Profile> profile_;
+ std::deque<metrics::ChromeUserMetricsExtension> metrics_logs_;
+ base::OnceClosure on_new_log_;
+};
+
+IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, ProtoHasExpectedFields) {
+ metrics::ChromeUserMetricsExtension log = WaitForNextMetricsLog();
+ EXPECT_EQ(metrics::ChromeUserMetricsExtension::ANDROID_WEBLAYER,
+ log.product());
+ EXPECT_TRUE(log.has_client_id());
+ EXPECT_TRUE(log.has_session_id());
+
+ const metrics::SystemProfileProto& system_profile = log.system_profile();
+ EXPECT_TRUE(system_profile.has_build_timestamp());
+ EXPECT_TRUE(system_profile.has_app_version());
+ EXPECT_TRUE(system_profile.has_channel());
+ EXPECT_TRUE(system_profile.has_install_date());
+ EXPECT_TRUE(system_profile.has_application_locale());
+ EXPECT_EQ("Android", system_profile.os().name());
+ EXPECT_TRUE(system_profile.os().has_version());
+ EXPECT_TRUE(system_profile.hardware().has_system_ram_mb());
+ EXPECT_TRUE(system_profile.hardware().has_hardware_class());
+ EXPECT_TRUE(system_profile.hardware().has_screen_count());
+ EXPECT_TRUE(system_profile.hardware().has_primary_screen_width());
+ EXPECT_TRUE(system_profile.hardware().has_primary_screen_height());
+ EXPECT_TRUE(system_profile.hardware().has_primary_screen_scale_factor());
+ EXPECT_TRUE(system_profile.hardware().has_cpu_architecture());
+ EXPECT_TRUE(system_profile.hardware().cpu().has_vendor_name());
+ EXPECT_TRUE(system_profile.hardware().cpu().has_signature());
+ EXPECT_TRUE(system_profile.hardware().cpu().has_num_cores());
+ EXPECT_TRUE(system_profile.hardware().cpu().has_is_hypervisor());
+ EXPECT_TRUE(system_profile.hardware().gpu().has_driver_version());
+ EXPECT_TRUE(system_profile.hardware().gpu().has_gl_vendor());
+ EXPECT_TRUE(system_profile.hardware().gpu().has_gl_renderer());
+}
+
+IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, PageLoadsEnableMultipleUploads) {
+ WaitForNextMetricsLog();
+
+ // At this point, the MetricsService should be asleep, and should not have
+ // created any more metrics logs.
+ ASSERT_EQ(0u, GetNumLogs());
+
+ // The start of a page load should be enough to indicate to the MetricsService
+ // that the app is "in use" and it's OK to upload the next record. No need to
+ // wait for onPageFinished, since this behavior should be gated on
+ // NOTIFICATION_LOAD_START.
+ shell()->tab()->GetNavigationController()->Navigate(GURL("about:blank"));
+
+ // This may take slightly longer than UPLOAD_INTERVAL_MS, due to the time
+ // spent processing the metrics log, but should be well within the timeout
+ // (unless something is broken).
+ WaitForNextMetricsLog();
+
+ // If we get here, we got a second metrics log (and the test may pass). If
+ // there was no second metrics log, then the above call will check fail with a
+ // timeout. We should not assert the logs are empty however, because it's
+ // possible we got a metrics log between onPageStarted & onPageFinished, in
+ // which case onPageFinished would *also* wake up the metrics service, and we
+ // might potentially have a third metrics log in the queue.
+}
+
+IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, NavigationIncrementsPageLoadCount) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ metrics::ChromeUserMetricsExtension log = WaitForNextMetricsLog();
+ // The initial log should not have a page load count (because nothing was
+ // loaded).
+ {
+ const metrics::SystemProfileProto& system_profile = log.system_profile();
+ ASSERT_TRUE(system_profile.has_stability());
+ EXPECT_EQ(0, system_profile.stability().page_load_count());
+ }
+
+ // Loading a page should increment the page load count.
+ NavigateAndWaitForCompletion(
+ embedded_test_server()->GetURL("/simple_page.html"), shell());
+ log = WaitForNextMetricsLog();
+ {
+ const metrics::SystemProfileProto& system_profile = log.system_profile();
+ ASSERT_TRUE(system_profile.has_stability());
+ EXPECT_EQ(1, system_profile.stability().page_load_count());
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, RendererHistograms) {
+ base::HistogramTester histogram_tester;
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ NavigateAndWaitForCompletion(
+ embedded_test_server()->GetURL("/simple_page.html"), shell());
+
+ uint64_t hash = base::HashMetricName("Android.SeccompStatus.RendererSandbox");
+
+ bool collect_final_metrics_for_log_called = false;
+
+ WebLayerMetricsServiceClient::GetInstance()
+ ->SetCollectFinalMetricsForLogClosureForTesting(
+ base::BindLambdaForTesting(
+ [&]() { collect_final_metrics_for_log_called = true; }));
+
+ // Not every WaitForNextMetricsLog call will end up calling
+ // MetricsServiceClient::CollectFinalMetricsForLog since there may already be
+ // staged logs to send (see ReportingService::SendNextLog). Since we need to
+ // wait for CollectFinalMetricsForLog to be run after the navigate call above,
+ // keep calling WaitForNextMetricsLog until CollectFinalMetricsForLog is
+ // called.
+ metrics::ChromeUserMetricsExtension uma_log;
+ while (!collect_final_metrics_for_log_called)
+ uma_log = WaitForNextMetricsLog();
+
+ ASSERT_TRUE(HasHistogramWithHash(uma_log, hash));
+}
+
+class MetricsBrowserTestWithUserOptOut : public MetricsBrowserTest {
+ bool HasUserConsent() override { return false; }
+};
+
+IN_PROC_BROWSER_TEST_F(MetricsBrowserTestWithUserOptOut, MetricsNotRecorded) {
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(0u, GetNumLogs());
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/android/metrics/metrics_test_helper.cc b/chromium/weblayer/browser/android/metrics/metrics_test_helper.cc
new file mode 100644
index 00000000000..bd0eb5b038d
--- /dev/null
+++ b/chromium/weblayer/browser/android/metrics/metrics_test_helper.cc
@@ -0,0 +1,79 @@
+// Copyright 2020 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 "weblayer/browser/android/metrics/metrics_test_helper.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/no_destructor.h"
+#include "base/run_loop.h"
+#include "weblayer/browser/profile_impl.h"
+#include "weblayer/test/weblayer_browsertests_jni/MetricsTestHelper_jni.h"
+
+namespace weblayer {
+
+namespace {
+
+OnLogsMetricsCallback& GetOnLogMetricsCallback() {
+ static base::NoDestructor<OnLogsMetricsCallback> s_callback;
+ return *s_callback;
+}
+
+ProfileImpl* GetProfileByName(const std::string& name) {
+ for (auto* profile : ProfileImpl::GetAllProfiles()) {
+ if (profile->name() == name)
+ return profile;
+ }
+
+ return nullptr;
+}
+
+} // namespace
+
+void InstallTestGmsBridge(bool has_user_consent,
+ const OnLogsMetricsCallback on_log_metrics) {
+ GetOnLogMetricsCallback() = on_log_metrics;
+ Java_MetricsTestHelper_installTestGmsBridge(
+ base::android::AttachCurrentThread(), has_user_consent);
+}
+
+void RemoveTestGmsBridge() {
+ Java_MetricsTestHelper_removeTestGmsBridge(
+ base::android::AttachCurrentThread());
+ GetOnLogMetricsCallback().Reset();
+}
+
+ProfileImpl* CreateProfile(const std::string& name) {
+ DCHECK(!GetProfileByName(name));
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_MetricsTestHelper_createProfile(
+ env, base::android::ConvertUTF8ToJavaString(env, name));
+ ProfileImpl* profile = GetProfileByName(name);
+ // Creating a profile may involve storage partition initialization. Wait for
+ // the initialization to be completed.
+ base::RunLoop().RunUntilIdle();
+ return profile;
+}
+void DestroyProfile(const std::string& name) {
+ DCHECK(GetProfileByName(name));
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_MetricsTestHelper_destroyProfile(
+ env, base::android::ConvertUTF8ToJavaString(env, name));
+}
+
+void JNI_MetricsTestHelper_OnLogMetrics(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jbyteArray>& data) {
+ auto& callback = GetOnLogMetricsCallback();
+ if (!callback)
+ return;
+
+ metrics::ChromeUserMetricsExtension proto;
+ jbyte* src_bytes = env->GetByteArrayElements(data, nullptr);
+ proto.ParseFromArray(src_bytes, env->GetArrayLength(data.obj()));
+ env->ReleaseByteArrayElements(data, src_bytes, JNI_ABORT);
+ callback.Run(proto);
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/android/metrics/metrics_test_helper.h b/chromium/weblayer/browser/android/metrics/metrics_test_helper.h
new file mode 100644
index 00000000000..ed398ce24de
--- /dev/null
+++ b/chromium/weblayer/browser/android/metrics/metrics_test_helper.h
@@ -0,0 +1,37 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_ANDROID_METRICS_METRICS_TEST_HELPER_H_
+#define WEBLAYER_BROWSER_ANDROID_METRICS_METRICS_TEST_HELPER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
+
+namespace weblayer {
+class ProfileImpl;
+
+// Various utilities to bridge to Java code for metrics related tests.
+
+using OnLogsMetricsCallback =
+ base::RepeatingCallback<void(metrics::ChromeUserMetricsExtension)>;
+
+// Call this in the SetUp() test harness method to install the test
+// GmsBridge and to set the metrics user consent state.
+void InstallTestGmsBridge(
+ bool has_user_consent,
+ const OnLogsMetricsCallback on_log_metrics = OnLogsMetricsCallback());
+
+// Call this in the TearDown() test harness method to remove the GmsBridge.
+void RemoveTestGmsBridge();
+
+// See Profile::Create()'s comments for the semantics of |name|.
+ProfileImpl* CreateProfile(const std::string& name);
+
+void DestroyProfile(const std::string& name);
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_ANDROID_METRICS_METRICS_TEST_HELPER_H_
diff --git a/chromium/weblayer/browser/ukm_browsertest.cc b/chromium/weblayer/browser/android/metrics/ukm_browsertest.cc
index 52b734a4559..53bd2203807 100644
--- a/chromium/weblayer/browser/ukm_browsertest.cc
+++ b/chromium/weblayer/browser/android/metrics/ukm_browsertest.cc
@@ -4,29 +4,16 @@
#include "base/test/bind_test_util.h"
#include "components/ukm/ukm_test_helper.h"
+#include "weblayer/browser/android/metrics/metrics_test_helper.h"
#include "weblayer/browser/android/metrics/weblayer_metrics_service_client.h"
#include "weblayer/browser/profile_impl.h"
#include "weblayer/public/navigation_controller.h"
#include "weblayer/public/tab.h"
-#include "weblayer/shell/android/browsertests_apk/metrics_test_helper.h"
#include "weblayer/shell/browser/shell.h"
#include "weblayer/test/weblayer_browser_test.h"
namespace weblayer {
-namespace {
-
-ProfileImpl* GetProfileByName(const std::string& name) {
- for (auto* profile : ProfileImpl::GetAllProfiles()) {
- if (profile->name() == name)
- return profile;
- }
-
- return nullptr;
-}
-
-} // namespace
-
class UkmBrowserTest : public WebLayerBrowserTest {
public:
void SetUp() override {
@@ -90,8 +77,8 @@ IN_PROC_BROWSER_TEST_F(UkmBrowserTest, RegularPlusIncognitoCheck) {
EXPECT_FALSE(ukm_test_helper.IsRecordingEnabled());
// Creating another regular profile mustn't enable UKM.
- CreateProfile("foo");
- GetProfileByName("foo")->SetBooleanSetting(SettingType::UKM_ENABLED, true);
+ auto* profile = CreateProfile("foo");
+ profile->SetBooleanSetting(SettingType::UKM_ENABLED, true);
EXPECT_FALSE(ukm_test_helper.IsRecordingEnabled());
// Note WebLayer can only have one incognito profile so we can't test creating
@@ -116,8 +103,8 @@ IN_PROC_BROWSER_TEST_F(UkmBrowserTest, IncognitoPlusRegularCheck) {
CreateProfile(std::string());
EXPECT_FALSE(ukm_test_helper.IsRecordingEnabled());
- CreateProfile("foo");
- GetProfileByName("foo")->SetBooleanSetting(SettingType::UKM_ENABLED, true);
+ auto* profile = CreateProfile("foo");
+ profile->SetBooleanSetting(SettingType::UKM_ENABLED, true);
EXPECT_FALSE(ukm_test_helper.IsRecordingEnabled());
DestroyProfile(std::string());
diff --git a/chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.cc b/chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.cc
index 569fe1d44e2..4cb35797b17 100644
--- a/chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.cc
+++ b/chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.cc
@@ -10,6 +10,8 @@
#include "base/base64.h"
#include "base/no_destructor.h"
+#include "components/metrics/content/content_stability_metrics_provider.h"
+#include "components/metrics/content/extensions_helper.h"
#include "components/metrics/metrics_provider.h"
#include "components/metrics/metrics_service.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
@@ -150,10 +152,13 @@ int WebLayerMetricsServiceClient::GetPackageNameLimitRatePerMille() {
void WebLayerMetricsServiceClient::RegisterAdditionalMetricsProviders(
metrics::MetricsService* service) {
+ service->RegisterMetricsProvider(
+ std::make_unique<metrics::ContentStabilityMetricsProvider>(pref_service(),
+ nullptr));
service->RegisterMetricsProvider(std::make_unique<PageLoadMetricsProvider>());
}
-bool WebLayerMetricsServiceClient::EnablePersistentHistograms() {
+bool WebLayerMetricsServiceClient::IsPersistentHistogramsEnabled() {
return true;
}
diff --git a/chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.h b/chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.h
index a25c0516ceb..09db1604fcb 100644
--- a/chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.h
+++ b/chromium/weblayer/browser/android/metrics/weblayer_metrics_service_client.h
@@ -48,7 +48,7 @@ class WebLayerMetricsServiceClient
int GetPackageNameLimitRatePerMille() override;
void RegisterAdditionalMetricsProviders(
metrics::MetricsService* service) override;
- bool EnablePersistentHistograms() override;
+ bool IsPersistentHistogramsEnabled() override;
bool IsOffTheRecordSessionActive() override;
scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
diff --git a/chromium/weblayer/browser/android/resource_mapper.cc b/chromium/weblayer/browser/android/resource_mapper.cc
index ae5bcdf81d4..aeeb6fbbf99 100644
--- a/chromium/weblayer/browser/android/resource_mapper.cc
+++ b/chromium/weblayer/browser/android/resource_mapper.cc
@@ -41,6 +41,7 @@ void ConstructMap() {
#include "components/resources/android/blocked_content_resource_id.h"
#include "components/resources/android/page_info_resource_id.h"
#include "components/resources/android/permissions_resource_id.h"
+#include "components/resources/android/sms_resource_id.h"
#undef LINK_RESOURCE_ID
#undef DECLARE_RESOURCE_ID
// Make sure ID list sizes match up.
diff --git a/chromium/weblayer/browser/autofill_client_impl.cc b/chromium/weblayer/browser/autofill_client_impl.cc
index f049ffa513f..cd7e3035575 100644
--- a/chromium/weblayer/browser/autofill_client_impl.cc
+++ b/chromium/weblayer/browser/autofill_client_impl.cc
@@ -69,6 +69,11 @@ autofill::AddressNormalizer* AutofillClientImpl::GetAddressNormalizer() {
return nullptr;
}
+const GURL& AutofillClientImpl::GetLastCommittedURL() {
+ NOTREACHED();
+ return GURL::EmptyGURL();
+}
+
security_state::SecurityLevel
AutofillClientImpl::GetSecurityLevelForUmaHistograms() {
NOTREACHED();
@@ -92,13 +97,13 @@ void AutofillClientImpl::OnUnmaskVerificationResult(PaymentsRpcResult result) {
#if !defined(OS_ANDROID)
std::vector<std::string>
-AutofillClientImpl::GetMerchantWhitelistForVirtualCards() {
+AutofillClientImpl::GetAllowedMerchantsForVirtualCards() {
NOTREACHED();
return std::vector<std::string>();
}
std::vector<std::string>
-AutofillClientImpl::GetBinRangeWhitelistForVirtualCards() {
+AutofillClientImpl::GetAllowedBinRangesForVirtualCards() {
NOTREACHED();
return std::vector<std::string>();
}
diff --git a/chromium/weblayer/browser/autofill_client_impl.h b/chromium/weblayer/browser/autofill_client_impl.h
index c5edc4a218a..f6b57dabdea 100644
--- a/chromium/weblayer/browser/autofill_client_impl.h
+++ b/chromium/weblayer/browser/autofill_client_impl.h
@@ -35,6 +35,7 @@ class AutofillClientImpl
ukm::UkmRecorder* GetUkmRecorder() override;
ukm::SourceId GetUkmSourceId() override;
autofill::AddressNormalizer* GetAddressNormalizer() override;
+ const GURL& GetLastCommittedURL() override;
security_state::SecurityLevel GetSecurityLevelForUmaHistograms() override;
void ShowAutofillSettings(bool show_credit_card_settings) override;
@@ -45,8 +46,8 @@ class AutofillClientImpl
void OnUnmaskVerificationResult(PaymentsRpcResult result) override;
#if !defined(OS_ANDROID)
- std::vector<std::string> GetMerchantWhitelistForVirtualCards() override;
- std::vector<std::string> GetBinRangeWhitelistForVirtualCards() override;
+ std::vector<std::string> GetAllowedMerchantsForVirtualCards() override;
+ std::vector<std::string> GetAllowedBinRangesForVirtualCards() override;
void ShowLocalCardMigrationDialog(
base::OnceClosure show_migration_dialog_closure) override;
diff --git a/chromium/weblayer/browser/browser_context_impl.cc b/chromium/weblayer/browser/browser_context_impl.cc
index 0e99612fdce..bbb9a179615 100644
--- a/chromium/weblayer/browser/browser_context_impl.cc
+++ b/chromium/weblayer/browser/browser_context_impl.cc
@@ -26,7 +26,7 @@
#include "components/translate/core/browser/translate_prefs.h"
#include "components/user_prefs/user_prefs.h"
#include "components/variations/variations_client.h"
-#include "components/variations/variations_http_header_provider.h"
+#include "components/variations/variations_ids_provider.h"
#include "content/public/browser/device_service.h"
#include "content/public/browser/download_request_utils.h"
#include "content/public/browser/resource_context.h"
@@ -34,6 +34,7 @@
#include "weblayer/browser/browsing_data_remover_delegate.h"
#include "weblayer/browser/browsing_data_remover_delegate_factory.h"
#include "weblayer/browser/client_hints_factory.h"
+#include "weblayer/browser/default_search_engine.h"
#include "weblayer/browser/permissions/permission_manager_factory.h"
#include "weblayer/browser/stateful_ssl_host_state_delegate_factory.h"
#include "weblayer/public/common/switches.h"
@@ -69,6 +70,9 @@ void BindWakeLockProvider(
} // namespace
namespace prefs {
+// Used to persist the public SettingType::NETWORK_PREDICTION_ENABLED API.
+const char kNoStatePrefetchEnabled[] = "weblayer.network_prediction_enabled";
+
// Used to persist the public SettingType::UKM_ENABLED API.
const char kUkmEnabled[] = "weblayer.ukm_enabled";
} // namespace prefs
@@ -94,6 +98,12 @@ BrowserContextImpl::BrowserContextImpl(ProfileImpl* profile_impl,
this);
site_isolation::SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(this);
+
+ // Set the DSE permissions every time the browser context is created for
+ // simplicity. These permissions are not editable in site settings, so should
+ // not ever be changed by the user. The site settings entry will link to the
+ // client app's system level permissions page to handle these.
+ ResetDsePermissions(this);
}
BrowserContextImpl::~BrowserContextImpl() {
@@ -240,6 +250,7 @@ void BrowserContextImpl::CreateUserPrefService() {
void BrowserContextImpl::RegisterPrefs(
user_prefs::PrefRegistrySyncable* pref_registry) {
+ pref_registry->RegisterBooleanPref(prefs::kNoStatePrefetchEnabled, true);
pref_registry->RegisterBooleanPref(prefs::kUkmEnabled, false);
// This pref is used by captive_portal::CaptivePortalService (as well as other
@@ -285,7 +296,7 @@ class BrowserContextImpl::WebLayerVariationsClient
}
std::string GetVariationsHeader() const override {
- return variations::VariationsHttpHeaderProvider::GetInstance()
+ return variations::VariationsIdsProvider::GetInstance()
->GetClientDataHeader(IsSignedIn());
}
diff --git a/chromium/weblayer/browser/browser_context_impl.h b/chromium/weblayer/browser/browser_context_impl.h
index 7d888462025..7a8eba34e29 100644
--- a/chromium/weblayer/browser/browser_context_impl.h
+++ b/chromium/weblayer/browser/browser_context_impl.h
@@ -23,6 +23,7 @@ class ResourceContextImpl;
namespace prefs {
// WebLayer specific pref names.
+extern const char kNoStatePrefetchEnabled[];
extern const char kUkmEnabled[];
} // namespace prefs
diff --git a/chromium/weblayer/browser/browser_controls_container_view.cc b/chromium/weblayer/browser/browser_controls_container_view.cc
index 81a1f9e9626..a4335283fd8 100644
--- a/chromium/weblayer/browser/browser_controls_container_view.cc
+++ b/chromium/weblayer/browser/browser_controls_container_view.cc
@@ -52,6 +52,21 @@ int BrowserControlsContainerView::GetControlsHeight() {
return controls_layer_ ? controls_layer_->bounds().height() : 0;
}
+int BrowserControlsContainerView::GetMinHeight() {
+ return Java_BrowserControlsContainerView_getMinHeight(
+ AttachCurrentThread(), java_browser_controls_container_view_);
+}
+
+bool BrowserControlsContainerView::OnlyExpandControlsAtPageTop() {
+ return Java_BrowserControlsContainerView_onlyExpandControlsAtPageTop(
+ AttachCurrentThread(), java_browser_controls_container_view_);
+}
+
+bool BrowserControlsContainerView::ShouldAnimateBrowserControlsHeightChanges() {
+ return Java_BrowserControlsContainerView_shouldAnimateBrowserControlsHeightChanges(
+ AttachCurrentThread(), java_browser_controls_container_view_);
+}
+
int BrowserControlsContainerView::GetContentHeightDelta() {
if (!controls_layer_ || !web_contents())
return 0;
diff --git a/chromium/weblayer/browser/browser_controls_container_view.h b/chromium/weblayer/browser/browser_controls_container_view.h
index 9231531499d..ed73606d75d 100644
--- a/chromium/weblayer/browser/browser_controls_container_view.h
+++ b/chromium/weblayer/browser/browser_controls_container_view.h
@@ -37,6 +37,17 @@ class BrowserControlsContainerView : public content::WebContentsObserver {
// Height needed to display the control.
int GetControlsHeight();
+ // Returns the minimum height the browser controls can collapse to.
+ int GetMinHeight();
+
+ // Returns true if the browser controls should only expand when the page
+ // contents are scrolled to the top.
+ bool OnlyExpandControlsAtPageTop();
+
+ // Returns true if height or offset changes to the browser controls should
+ // be animated.
+ bool ShouldAnimateBrowserControlsHeightChanges();
+
// Returns the amount of vertical space to take away from the contents.
int GetContentHeightDelta();
@@ -54,8 +65,7 @@ class BrowserControlsContainerView : public content::WebContentsObserver {
// Sets the offsets of the controls and content. See
// BrowserControlsContainerView's javadoc for details on this.
- void SetTopControlsOffset(JNIEnv* env,
- int content_offset_y);
+ void SetTopControlsOffset(JNIEnv* env, int content_offset_y);
void SetBottomControlsOffset(JNIEnv* env);
// Sets the size of |controls_layer_|.
diff --git a/chromium/weblayer/browser/browser_controls_navigation_state_handler.cc b/chromium/weblayer/browser/browser_controls_navigation_state_handler.cc
index a049f38ca42..dd82111b17e 100644
--- a/chromium/weblayer/browser/browser_controls_navigation_state_handler.cc
+++ b/chromium/weblayer/browser/browser_controls_navigation_state_handler.cc
@@ -61,8 +61,10 @@ void BrowserControlsNavigationStateHandler::DidStartNavigation(
void BrowserControlsNavigationStateHandler::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
if (navigation_handle->IsInMainFrame()) {
- if (navigation_handle->HasCommitted())
- is_showing_error_page_ = navigation_handle->IsErrorPage();
+ if (!navigation_handle->HasCommitted()) {
+ // There will be no DidFinishLoad or DidFailLoad, so hide the topview
+ ScheduleStopDelayedForceShow();
+ }
delegate_->OnUpdateBrowserControlsStateBecauseOfProcessSwitch(
navigation_handle->HasCommitted());
}
@@ -81,6 +83,10 @@ void BrowserControlsNavigationStateHandler::DidFailLoad(
content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code) {
+ const bool is_main_frame =
+ render_frame_host->GetMainFrame() == render_frame_host;
+ if (is_main_frame)
+ ScheduleStopDelayedForceShow();
if (render_frame_host->IsCurrent() &&
(render_frame_host == web_contents()->GetMainFrame())) {
UpdateState();
diff --git a/chromium/weblayer/browser/browser_controls_navigation_state_handler.h b/chromium/weblayer/browser/browser_controls_navigation_state_handler.h
index 0ad3b319b3e..de7edb0fa6e 100644
--- a/chromium/weblayer/browser/browser_controls_navigation_state_handler.h
+++ b/chromium/weblayer/browser/browser_controls_navigation_state_handler.h
@@ -82,9 +82,6 @@ class BrowserControlsNavigationStateHandler
// Last value supplied to the delegate.
base::Optional<content::BrowserControlsState> last_state_;
- // True if an error page is showing.
- bool is_showing_error_page_ = false;
-
// This is cached as WebContents::IsCrashed() does not always return the
// right thing.
bool is_crashed_ = false;
diff --git a/chromium/weblayer/browser/browser_impl.cc b/chromium/weblayer/browser/browser_impl.cc
index b7f5dc490b3..04c775fb266 100644
--- a/chromium/weblayer/browser/browser_impl.cc
+++ b/chromium/weblayer/browser/browser_impl.cc
@@ -12,6 +12,7 @@
#include "base/path_service.h"
#include "base/stl_util.h"
#include "components/base32/base32.h"
+#include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h"
#include "weblayer/browser/browser_context_impl.h"
#include "weblayer/browser/browser_list.h"
@@ -114,6 +115,11 @@ BrowserImpl::~BrowserImpl() {
TabImpl* BrowserImpl::CreateTabForSessionRestore(
std::unique_ptr<content::WebContents> web_contents,
const std::string& guid) {
+ if (!web_contents) {
+ content::WebContents::CreateParams create_params(
+ profile_->GetBrowserContext());
+ web_contents = content::WebContents::Create(create_params);
+ }
std::unique_ptr<TabImpl> tab =
std::make_unique<TabImpl>(profile_, std::move(web_contents), guid);
#if defined(OS_ANDROID)
@@ -265,6 +271,12 @@ void BrowserImpl::SetWebPreferences(content::WebPreferences* prefs) {
#endif
}
+#if defined(OS_ANDROID)
+void BrowserImpl::DestroyTabFromJava(Tab* tab) {
+ RemoveTab(tab);
+}
+#endif
+
void BrowserImpl::AddTab(Tab* tab) {
DCHECK(tab);
TabImpl* tab_impl = static_cast<TabImpl*>(tab);
@@ -277,7 +289,12 @@ void BrowserImpl::AddTab(Tab* tab) {
}
void BrowserImpl::DestroyTab(Tab* tab) {
+#if defined(OS_ANDROID)
+ Java_BrowserImpl_destroyTabImpl(AttachCurrentThread(), java_impl_,
+ static_cast<TabImpl*>(tab)->GetJavaTab());
+#else
RemoveTab(tab);
+#endif
}
void BrowserImpl::SetActiveTab(Tab* tab) {
diff --git a/chromium/weblayer/browser/browser_impl.h b/chromium/weblayer/browser/browser_impl.h
index f5487af1cbc..02363c113c0 100644
--- a/chromium/weblayer/browser/browser_impl.h
+++ b/chromium/weblayer/browser/browser_impl.h
@@ -97,6 +97,14 @@ class BrowserImpl : public Browser {
bool GetPasswordEchoEnabled();
void SetWebPreferences(content::WebPreferences* prefs);
+#if defined(OS_ANDROID)
+ // On Android the Java Tab class owns the C++ Tab. DestroyTab() calls to the
+ // Java Tab class to initiate deletion. This function is called from the Java
+ // side, and must not call DestroyTab(), otherwise we get stuck in infinite
+ // recursion.
+ void DestroyTabFromJava(Tab* tab);
+#endif
+
// Browser:
void AddTab(Tab* tab) override;
void DestroyTab(Tab* tab) override;
diff --git a/chromium/weblayer/browser/browser_main_parts_impl.cc b/chromium/weblayer/browser/browser_main_parts_impl.cc
index 7f9e8467a13..b8d317ae48f 100644
--- a/chromium/weblayer/browser/browser_main_parts_impl.cc
+++ b/chromium/weblayer/browser/browser_main_parts_impl.cc
@@ -6,7 +6,7 @@
#include "base/base_switches.h"
#include "base/bind.h"
-#include "base/message_loop/message_loop_current.h"
+#include "base/task/current_thread.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
@@ -19,6 +19,7 @@
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/main_function_params.h"
+#include "content/public/common/page_visibility_state.h"
#include "content/public/common/url_constants.h"
#include "services/service_manager/embedder/result_codes.h"
#include "ui/base/resource/resource_bundle.h"
@@ -27,6 +28,8 @@
#include "weblayer/browser/feature_list_creator.h"
#include "weblayer/browser/host_content_settings_map_factory.h"
#include "weblayer/browser/i18n_util.h"
+#include "weblayer/browser/no_state_prefetch/prerender_link_manager_factory.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
#include "weblayer/browser/permissions/weblayer_permissions_client.h"
#include "weblayer/browser/stateful_ssl_host_state_delegate_factory.h"
#include "weblayer/browser/translate_accept_languages_factory.h"
@@ -54,6 +57,7 @@
#include "ui/base/x/x11_util.h" // nogncheck
#endif
#if defined(USE_AURA) && defined(USE_X11)
+#include "ui/base/ui_base_features.h"
#include "ui/events/devices/x11/touch_factory_x11.h" // nogncheck
#endif
#if !defined(OS_CHROMEOS) && defined(USE_AURA) && defined(OS_LINUX)
@@ -80,6 +84,8 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
CookieSettingsFactory::GetInstance();
TranslateAcceptLanguagesFactory::GetInstance();
TranslateRankerFactory::GetInstance();
+ PrerenderLinkManagerFactory::GetInstance();
+ PrerenderManagerFactory::GetInstance();
}
void StopMessageLoop(base::OnceClosure quit_closure) {
@@ -130,7 +136,8 @@ int BrowserMainPartsImpl::PreCreateThreads() {
void BrowserMainPartsImpl::PreMainMessageLoopStart() {
#if defined(USE_AURA) && defined(USE_X11)
- ui::TouchFactory::SetTouchDeviceListFromCommandLine();
+ if (!features::IsUsingOzonePlatform())
+ ui::TouchFactory::SetTouchDeviceListFromCommandLine();
#endif
}
@@ -138,7 +145,8 @@ int BrowserMainPartsImpl::PreEarlyInitialization() {
browser_process_ = std::make_unique<BrowserProcess>(std::move(local_state_));
#if defined(USE_X11)
- ui::SetDefaultX11ErrorHandlers();
+ if (!features::IsUsingOzonePlatform())
+ ui::SetDefaultX11ErrorHandlers();
#endif
#if defined(USE_AURA) && defined(OS_LINUX)
ui::InitializeInputMethodForTesting();
diff --git a/chromium/weblayer/browser/browser_process.cc b/chromium/weblayer/browser/browser_process.cc
index b9fbde8f436..ac3929137cc 100644
--- a/chromium/weblayer/browser/browser_process.cc
+++ b/chromium/weblayer/browser/browser_process.cc
@@ -14,6 +14,7 @@
#include "content/public/browser/network_service_instance.h"
#include "services/network/public/cpp/network_quality_tracker.h"
#include "weblayer/browser/system_network_context_manager.h"
+#include "weblayer/browser/user_agent.h"
#if defined(OS_ANDROID)
#include "weblayer/browser/safe_browsing/safe_browsing_service.h"
@@ -99,12 +100,12 @@ void BrowserProcess::CreateNetworkQualityObserver() {
}
#if defined(OS_ANDROID)
-SafeBrowsingService* BrowserProcess::GetSafeBrowsingService(
- std::string user_agent) {
+SafeBrowsingService* BrowserProcess::GetSafeBrowsingService() {
if (!safe_browsing_service_) {
// Create and initialize safe_browsing_service on first get.
// Note: Initialize() needs to happen on UI thread.
- safe_browsing_service_ = std::make_unique<SafeBrowsingService>(user_agent);
+ safe_browsing_service_ =
+ std::make_unique<SafeBrowsingService>(GetUserAgent());
safe_browsing_service_->Initialize();
}
return safe_browsing_service_.get();
diff --git a/chromium/weblayer/browser/browser_process.h b/chromium/weblayer/browser/browser_process.h
index 2cd3dd1d354..08540a6520d 100644
--- a/chromium/weblayer/browser/browser_process.h
+++ b/chromium/weblayer/browser/browser_process.h
@@ -49,7 +49,7 @@ class BrowserProcess {
network::NetworkQualityTracker* GetNetworkQualityTracker();
#if defined(OS_ANDROID)
- SafeBrowsingService* GetSafeBrowsingService(std::string user_agent);
+ SafeBrowsingService* GetSafeBrowsingService();
void StopSafeBrowsingService();
#endif
diff --git a/chromium/weblayer/browser/browsing_data_remover_delegate.cc b/chromium/weblayer/browser/browsing_data_remover_delegate.cc
index 2a466fe8cad..66dc3ae5bb8 100644
--- a/chromium/weblayer/browser/browsing_data_remover_delegate.cc
+++ b/chromium/weblayer/browser/browsing_data_remover_delegate.cc
@@ -5,10 +5,20 @@
#include "weblayer/browser/browsing_data_remover_delegate.h"
#include "base/callback.h"
-#include "components/prefs/pref_service.h"
-#include "components/site_isolation//pref_names.h"
+#include "build/build_config.h"
+#include "components/browsing_data/content/browsing_data_helper.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browsing_data_filter_builder.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
+#include "weblayer/browser/browser_process.h"
+#include "weblayer/browser/default_search_engine.h"
+#include "weblayer/browser/favicon/favicon_service_impl.h"
+#include "weblayer/browser/favicon/favicon_service_impl_factory.h"
+#include "weblayer/browser/host_content_settings_map_factory.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
+#include "weblayer/browser/safe_browsing/safe_browsing_service.h"
namespace weblayer {
@@ -16,6 +26,8 @@ BrowsingDataRemoverDelegate::BrowsingDataRemoverDelegate(
content::BrowserContext* browser_context)
: browser_context_(browser_context) {}
+BrowsingDataRemoverDelegate::~BrowsingDataRemoverDelegate() = default;
+
BrowsingDataRemoverDelegate::EmbedderOriginTypeMatcher
BrowsingDataRemoverDelegate::GetOriginTypeMatcher() {
return EmbedderOriginTypeMatcher();
@@ -37,18 +49,82 @@ void BrowsingDataRemoverDelegate::RemoveEmbedderData(
uint64_t remove_mask,
content::BrowsingDataFilterBuilder* filter_builder,
uint64_t origin_type_mask,
- base::OnceClosure callback) {
+ base::OnceCallback<void(uint64_t)> callback) {
+ callback_ = std::move(callback);
+
// Note: if history is ever added to WebLayer, also remove isolated origins
// when history is cleared.
if (remove_mask & DATA_TYPE_ISOLATED_ORIGINS) {
- user_prefs::UserPrefs::Get(browser_context_)
- ->ClearPref(site_isolation::prefs::kUserTriggeredIsolatedOrigins);
- // Note that this does not clear these sites from the in-memory map in
- // ChildProcessSecurityPolicy, since that is not supported at runtime. That
- // list of isolated sites is not directly exposed to users, though, and
- // will be cleared on next restart.
+ browsing_data::RemoveSiteIsolationData(
+ user_prefs::UserPrefs::Get(browser_context_));
+ }
+
+ HostContentSettingsMap* host_content_settings_map =
+ HostContentSettingsMapFactory::GetForBrowserContext(browser_context_);
+
+ if (remove_mask & content::BrowsingDataRemover::DATA_TYPE_CACHE) {
+ browsing_data::RemovePrerenderCacheData(
+ PrerenderManagerFactory::GetForBrowserContext(browser_context_));
}
- std::move(callback).Run();
+
+ if (remove_mask & DATA_TYPE_FAVICONS) {
+ auto* service =
+ FaviconServiceImplFactory::GetForBrowserContext(browser_context_);
+ if (service) {
+ // The favicon database doesn't track enough information to remove
+ // favicons in a time range. Delete everything.
+ service->DeleteAndRecreateDatabase(CreateTaskCompletionClosure());
+ }
+ }
+
+ // We ignore the DATA_TYPE_COOKIES request if UNPROTECTED_WEB is not set,
+ // so that callers who request COOKIES_AND_SITE_DATA with PROTECTED_WEB
+ // don't accidentally remove the cookies that are associated with the
+ // UNPROTECTED_WEB origin. This is necessary because cookies are not separated
+ // between UNPROTECTED_WEB and PROTECTED_WEB.
+ if (remove_mask & content::BrowsingDataRemover::DATA_TYPE_COOKIES) {
+ network::mojom::NetworkContext* safe_browsing_context = nullptr;
+#if defined(OS_ANDROID)
+ auto* sb_service = BrowserProcess::GetInstance()->GetSafeBrowsingService();
+ if (sb_service)
+ safe_browsing_context = sb_service->GetNetworkContext();
+#endif
+ browsing_data::RemoveEmbedderCookieData(
+ delete_begin, delete_end, filter_builder, host_content_settings_map,
+ safe_browsing_context,
+ base::BindOnce(
+ &BrowsingDataRemoverDelegate::CreateTaskCompletionClosure,
+ base::Unretained(this)));
+ }
+
+ if (remove_mask & DATA_TYPE_SITE_SETTINGS) {
+ browsing_data::RemoveSiteSettingsData(delete_begin, delete_end,
+ host_content_settings_map);
+
+ // Reset the Default Search Engine permissions to their default.
+ ResetDsePermissions(browser_context_);
+ }
+
+ RunCallbackIfDone();
+}
+
+base::OnceClosure BrowsingDataRemoverDelegate::CreateTaskCompletionClosure() {
+ ++pending_tasks_;
+
+ return base::BindOnce(&BrowsingDataRemoverDelegate::OnTaskComplete,
+ weak_ptr_factory_.GetWeakPtr());
+}
+
+void BrowsingDataRemoverDelegate::OnTaskComplete() {
+ pending_tasks_--;
+ RunCallbackIfDone();
+}
+
+void BrowsingDataRemoverDelegate::RunCallbackIfDone() {
+ if (pending_tasks_ != 0)
+ return;
+
+ std::move(callback_).Run(/*failed_data_types=*/0);
}
} // namespace weblayer
diff --git a/chromium/weblayer/browser/browsing_data_remover_delegate.h b/chromium/weblayer/browser/browsing_data_remover_delegate.h
index c2a996debba..0672e4683f1 100644
--- a/chromium/weblayer/browser/browsing_data_remover_delegate.h
+++ b/chromium/weblayer/browser/browsing_data_remover_delegate.h
@@ -5,6 +5,8 @@
#ifndef WEBLAYER_BROWSER_BROWSING_DATA_REMOVER_DELEGATE_H_
#define WEBLAYER_BROWSER_BROWSING_DATA_REMOVER_DELEGATE_H_
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/browsing_data_remover_delegate.h"
@@ -28,10 +30,13 @@ class BrowsingDataRemoverDelegate : public content::BrowsingDataRemoverDelegate,
// WebLayer-specific datatypes.
DATA_TYPE_ISOLATED_ORIGINS = DATA_TYPE_EMBEDDER_BEGIN,
+ DATA_TYPE_FAVICONS = DATA_TYPE_EMBEDDER_BEGIN << 1,
+ DATA_TYPE_SITE_SETTINGS = DATA_TYPE_EMBEDDER_BEGIN << 2,
};
explicit BrowsingDataRemoverDelegate(
content::BrowserContext* browser_context);
+ ~BrowsingDataRemoverDelegate() override;
BrowsingDataRemoverDelegate(const BrowsingDataRemoverDelegate&) = delete;
BrowsingDataRemoverDelegate& operator=(const BrowsingDataRemoverDelegate&) =
@@ -47,10 +52,23 @@ class BrowsingDataRemoverDelegate : public content::BrowsingDataRemoverDelegate,
uint64_t remove_mask,
content::BrowsingDataFilterBuilder* filter_builder,
uint64_t origin_type_mask,
- base::OnceClosure callback) override;
+ base::OnceCallback<void(uint64_t)> callback) override;
private:
+ base::OnceClosure CreateTaskCompletionClosure();
+
+ void OnTaskComplete();
+
+ void RunCallbackIfDone();
+
content::BrowserContext* browser_context_ = nullptr;
+
+ int pending_tasks_ = 0;
+
+ // Completion callback to call when all data are deleted.
+ base::OnceCallback<void(uint64_t)> callback_;
+
+ base::WeakPtrFactory<BrowsingDataRemoverDelegate> weak_ptr_factory_{this};
};
} // namespace weblayer
diff --git a/chromium/weblayer/browser/client_hints_browsertest.cc b/chromium/weblayer/browser/client_hints_browsertest.cc
index 3aa644fe269..77e7711f9e0 100644
--- a/chromium/weblayer/browser/client_hints_browsertest.cc
+++ b/chromium/weblayer/browser/client_hints_browsertest.cc
@@ -142,7 +142,12 @@ IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
other_server.base_url(), GURL(), ContentSettingsType::CLIENT_HINTS,
std::string(), std::make_unique<base::Value>(setting->Clone()));
- // New server should now get client hints.
+ // Settings take affect after navigation only, so the header shouldn't be
+ // there yet.
+ EXPECT_EQ(GetSubresourceHeader("device-memory"), "None");
+
+ // After re-navigating, should have hints.
+ NavigateAndWaitForCompletion(other_server.GetURL("/echo"), shell());
CheckSubresourceHeaders();
}
diff --git a/chromium/weblayer/browser/confirm_infobar_android.cc b/chromium/weblayer/browser/confirm_infobar_android.cc
deleted file mode 100644
index 2ce1d44fa97..00000000000
--- a/chromium/weblayer/browser/confirm_infobar_android.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2020 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 "weblayer/browser/confirm_infobar_android.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/android/jni_string.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/android/window_android.h"
-#include "ui/gfx/android/java_bitmap.h"
-#include "ui/gfx/image/image.h"
-#include "weblayer/browser/infobar_service.h"
-#include "weblayer/browser/java/jni/ConfirmInfoBar_jni.h"
-
-using base::android::JavaParamRef;
-using base::android::ScopedJavaLocalRef;
-
-namespace weblayer {
-
-// InfoBarService -------------------------------------------------------------
-
-std::unique_ptr<infobars::InfoBar> InfoBarService::CreateConfirmInfoBar(
- std::unique_ptr<ConfirmInfoBarDelegate> delegate) {
- return std::make_unique<ConfirmInfoBar>(std::move(delegate));
-}
-
-// ConfirmInfoBar -------------------------------------------------------------
-
-ConfirmInfoBar::ConfirmInfoBar(std::unique_ptr<ConfirmInfoBarDelegate> delegate)
- : InfoBarAndroid(std::move(delegate)) {}
-
-ConfirmInfoBar::~ConfirmInfoBar() = default;
-
-base::string16 ConfirmInfoBar::GetTextFor(
- ConfirmInfoBarDelegate::InfoBarButton button) {
- ConfirmInfoBarDelegate* delegate = GetDelegate();
- return (delegate->GetButtons() & button) ? delegate->GetButtonLabel(button)
- : base::string16();
-}
-
-ConfirmInfoBarDelegate* ConfirmInfoBar::GetDelegate() {
- return delegate()->AsConfirmInfoBarDelegate();
-}
-
-ScopedJavaLocalRef<jobject> ConfirmInfoBar::CreateRenderInfoBar(JNIEnv* env) {
- ScopedJavaLocalRef<jstring> ok_button_text =
- base::android::ConvertUTF16ToJavaString(
- env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_OK));
- ScopedJavaLocalRef<jstring> cancel_button_text =
- base::android::ConvertUTF16ToJavaString(
- env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_CANCEL));
- ConfirmInfoBarDelegate* delegate = GetDelegate();
- ScopedJavaLocalRef<jstring> message_text =
- base::android::ConvertUTF16ToJavaString(env, delegate->GetMessageText());
- ScopedJavaLocalRef<jstring> link_text =
- base::android::ConvertUTF16ToJavaString(env, delegate->GetLinkText());
-
- ScopedJavaLocalRef<jobject> java_bitmap;
- if (delegate->GetIconId() == infobars::InfoBarDelegate::kNoIconID &&
- !delegate->GetIcon().IsEmpty()) {
- java_bitmap = gfx::ConvertToJavaBitmap(delegate->GetIcon().ToSkBitmap());
- }
-
- return Java_ConfirmInfoBar_create(env, GetJavaIconId(), java_bitmap,
- message_text, link_text, ok_button_text,
- cancel_button_text);
-}
-
-void ConfirmInfoBar::OnLinkClicked(JNIEnv* env,
- const JavaParamRef<jobject>& obj) {
- if (!owner())
- return; // We're closing; don't call anything, it might access the owner.
-
- if (GetDelegate()->LinkClicked(WindowOpenDisposition::NEW_FOREGROUND_TAB))
- RemoveSelf();
-}
-
-void ConfirmInfoBar::ProcessButton(int action) {
- if (!owner())
- return; // We're closing; don't call anything, it might access the owner.
-
- DCHECK((action == InfoBarAndroid::ACTION_OK) ||
- (action == InfoBarAndroid::ACTION_CANCEL));
- ConfirmInfoBarDelegate* delegate = GetDelegate();
- if ((action == InfoBarAndroid::ACTION_OK) ? delegate->Accept()
- : delegate->Cancel()) {
- RemoveSelf();
- }
-}
-
-} // namespace weblayer
diff --git a/chromium/weblayer/browser/confirm_infobar_android.h b/chromium/weblayer/browser/confirm_infobar_android.h
deleted file mode 100644
index 9611841ef3f..00000000000
--- a/chromium/weblayer/browser/confirm_infobar_android.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2020 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 WEBLAYER_BROWSER_CONFIRM_INFOBAR_ANDROID_H_
-#define WEBLAYER_BROWSER_CONFIRM_INFOBAR_ANDROID_H_
-
-#include "base/android/scoped_java_ref.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "weblayer/browser/infobar_android.h"
-
-namespace weblayer {
-
-class ConfirmInfoBar : public InfoBarAndroid {
- public:
- explicit ConfirmInfoBar(std::unique_ptr<ConfirmInfoBarDelegate> delegate);
- ~ConfirmInfoBar() override;
-
- protected:
- ConfirmInfoBarDelegate* GetDelegate();
- base::string16 GetTextFor(ConfirmInfoBarDelegate::InfoBarButton button);
-
- // InfoBarAndroid overrides.
- base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
- JNIEnv* env) override;
-
- void OnLinkClicked(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj) override;
-
- void ProcessButton(int action) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConfirmInfoBar);
-};
-
-} // namespace weblayer
-
-#endif // WEBLAYER_BROWSER_CONFIRM_INFOBAR_ANDROID_H_
diff --git a/chromium/weblayer/browser/content_browser_client_impl.cc b/chromium/weblayer/browser/content_browser_client_impl.cc
index 438122ad99b..0418225aad5 100644
--- a/chromium/weblayer/browser/content_browser_client_impl.cc
+++ b/chromium/weblayer/browser/content_browser_client_impl.cc
@@ -20,6 +20,7 @@
#include "components/blocked_content/popup_blocker.h"
#include "components/captive_portal/core/buildflags.h"
#include "components/embedder_support/switches.h"
+#include "components/error_page/content/browser/net_error_auto_reloader.h"
#include "components/network_time/network_time_tracker.h"
#include "components/page_load_metrics/browser/metrics_navigation_throttle.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
@@ -28,6 +29,9 @@
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service_factory.h"
#include "components/prefs/scoped_user_pref_update.h"
+#include "components/prerender/browser/prerender_manager.h"
+#include "components/prerender/common/prerender_url_loader_throttle.h"
+#include "components/security_interstitials/content/insecure_form_navigation_throttle.h"
#include "components/security_interstitials/content/ssl_cert_reporter.h"
#include "components/security_interstitials/content/ssl_error_handler.h"
#include "components/security_interstitials/content/ssl_error_navigation_throttle.h"
@@ -38,6 +42,7 @@
#include "components/user_prefs/user_prefs.h"
#include "components/variations/service/variations_service.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/devtools_manager_delegate.h"
#include "content/public/browser/generated_code_cache_settings.h"
@@ -46,7 +51,6 @@
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/tts_controller.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/service_names.mojom.h"
@@ -75,16 +79,20 @@
#include "weblayer/browser/http_auth_handler_impl.h"
#include "weblayer/browser/i18n_util.h"
#include "weblayer/browser/navigation_controller_impl.h"
+#include "weblayer/browser/navigation_error_navigation_throttle.h"
+#include "weblayer/browser/navigation_ui_data_impl.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
+#include "weblayer/browser/no_state_prefetch/prerender_utils.h"
+#include "weblayer/browser/page_specific_content_settings_delegate.h"
#include "weblayer/browser/password_manager_driver_factory.h"
#include "weblayer/browser/popup_navigation_delegate_impl.h"
#include "weblayer/browser/profile_impl.h"
+#include "weblayer/browser/signin_url_loader_throttle.h"
#include "weblayer/browser/system_network_context_manager.h"
#include "weblayer/browser/tab_impl.h"
-#include "weblayer/browser/tab_specific_content_settings_delegate.h"
#include "weblayer/browser/user_agent.h"
#include "weblayer/browser/web_contents_view_delegate_impl.h"
#include "weblayer/browser/weblayer_browser_interface_binders.h"
-#include "weblayer/browser/weblayer_content_browser_overlay_manifest.h"
#include "weblayer/browser/weblayer_security_blocking_page_factory.h"
#include "weblayer/browser/weblayer_speech_recognition_manager_delegate.h"
#include "weblayer/common/features.h"
@@ -118,6 +126,7 @@
#include "weblayer/browser/devtools_manager_delegate_android.h"
#include "weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.h"
#include "weblayer/browser/safe_browsing/safe_browsing_service.h"
+#include "weblayer/browser/tts_environment_android_impl.h"
#endif
#if defined(OS_LINUX) || defined(OS_ANDROID)
@@ -125,8 +134,8 @@
#endif
#if defined(OS_WIN)
+#include "sandbox/policy/win/sandbox_win.h"
#include "sandbox/win/src/sandbox.h"
-#include "services/service_manager/sandbox/win/sandbox_win.h"
#endif
#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
@@ -155,6 +164,16 @@ bool IsSafebrowsingSupported() {
return false;
}
+bool IsNetworkErrorAutoReloadEnabled() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kEnableAutoReload))
+ return true;
+ if (command_line.HasSwitch(switches::kDisableAutoReload))
+ return false;
+ return true;
+}
+
bool IsInHostedApp(content::WebContents* web_contents) {
return false;
}
@@ -227,6 +246,14 @@ void RegisterPrefs(PrefRegistrySimple* pref_registry) {
variations::VariationsService::RegisterPrefs(pref_registry);
}
+mojo::PendingRemote<prerender::mojom::PrerenderCanceler> GetPrerenderCanceler(
+ content::WebContents* web_contents) {
+ mojo::PendingRemote<prerender::mojom::PrerenderCanceler> canceler;
+ weblayer::PrerenderContentsFromWebContents(web_contents)
+ ->AddPrerenderCancelerReceiver(canceler.InitWithNewPipeAndPassReceiver());
+ return canceler;
+}
+
} // namespace
ContentBrowserClientImpl::ContentBrowserClientImpl(MainParams* params)
@@ -278,13 +305,6 @@ ContentBrowserClientImpl::GetDevToolsManagerDelegate() {
#endif
}
-base::Optional<service_manager::Manifest>
-ContentBrowserClientImpl::GetServiceManifestOverlay(base::StringPiece name) {
- if (name == content::mojom::kBrowserServiceName)
- return GetWebLayerContentBrowserOverlayManifest();
- return base::nullopt;
-}
-
void ContentBrowserClientImpl::LogWebFeatureForCurrentPage(
content::RenderFrameHost* render_frame_host,
blink::mojom::WebFeature feature) {
@@ -399,6 +419,23 @@ ContentBrowserClientImpl::CreateURLLoaderThrottles(
#endif
}
+ auto signin_throttle =
+ SigninURLLoaderThrottle::Create(browser_context, wc_getter);
+ if (signin_throttle)
+ result.push_back(std::move(signin_throttle));
+
+ // Create prerender URL throttle.
+ auto* web_contents = wc_getter.Run();
+ auto* prerender_contents = PrerenderContentsFromWebContents(web_contents);
+ if (prerender_contents && prerender_contents->prerender_mode() !=
+ prerender::mojom::PrerenderMode::kNoPrerender) {
+ result.push_back(std::make_unique<prerender::PrerenderURLLoaderThrottle>(
+ prerender_contents->prerender_mode(),
+ prerender::PrerenderHistograms::GetHistogramPrefix(
+ prerender_contents->origin()),
+ GetPrerenderCanceler(web_contents)));
+ }
+
return result;
}
@@ -450,6 +487,40 @@ ContentBrowserClientImpl::GetOriginsRequiringDedicatedProcess() {
return site_isolation::GetBrowserSpecificBuiltInIsolatedOrigins();
}
+bool ContentBrowserClientImpl::MayReuseHost(
+ content::RenderProcessHost* process_host) {
+ // If there is currently a prerender in progress for the host provided,
+ // it may not be shared. We require prerenders to be by themselves in a
+ // separate process so that we can monitor their resource usage.
+ prerender::PrerenderManager* prerender_manager =
+ PrerenderManagerFactory::GetForBrowserContext(
+ process_host->GetBrowserContext());
+ if (prerender_manager &&
+ !prerender_manager->MayReuseProcessHost(process_host)) {
+ return false;
+ }
+
+ return true;
+}
+
+void ContentBrowserClientImpl::OverridePageVisibilityState(
+ content::RenderFrameHost* render_frame_host,
+ content::PageVisibilityState* visibility_state) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(render_frame_host);
+ DCHECK(web_contents);
+
+ prerender::PrerenderManager* prerender_manager =
+ PrerenderManagerFactory::GetForBrowserContext(
+ web_contents->GetBrowserContext());
+ if (prerender_manager &&
+ prerender_manager->IsWebContentsPrerendering(web_contents, nullptr)) {
+ *visibility_state = content::PageVisibilityState::kHiddenButPainting;
+ }
+}
+
bool ContentBrowserClientImpl::ShouldDisableSiteIsolation() {
return site_isolation::SiteIsolationPolicy::
ShouldDisableSiteIsolationDueToMemoryThreshold();
@@ -563,6 +634,17 @@ ContentBrowserClientImpl::CreateThrottlesForNavigation(
std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
if (handle->IsInMainFrame()) {
+ NavigationUIDataImpl* navigation_ui_data =
+ static_cast<NavigationUIDataImpl*>(handle->GetNavigationUIData());
+ if ((!navigation_ui_data ||
+ !navigation_ui_data->disable_network_error_auto_reload()) &&
+ IsNetworkErrorAutoReloadEnabled()) {
+ auto auto_reload_throttle =
+ error_page::NetErrorAutoReloader::MaybeCreateThrottleFor(handle);
+ if (auto_reload_throttle)
+ throttles.push_back(std::move(auto_reload_throttle));
+ }
+
// MetricsNavigationThrottle requires that it runs before
// NavigationThrottles that may delay or cancel navigations, so only
// NavigationThrottles that don't delay or cancel navigations (e.g.
@@ -570,6 +652,10 @@ ContentBrowserClientImpl::CreateThrottlesForNavigation(
// behavior) should be added before MetricsNavigationThrottle.
throttles.push_back(
page_load_metrics::MetricsNavigationThrottle::Create(handle));
+ if (TabImpl::FromWebContents(handle->GetWebContents())) {
+ throttles.push_back(
+ std::make_unique<NavigationErrorNavigationThrottle>(handle));
+ }
}
// The next highest priority throttle *must* be this as it's responsible for
@@ -587,6 +673,15 @@ ContentBrowserClientImpl::CreateThrottlesForNavigation(
handle, std::make_unique<SSLCertReporterImpl>(),
base::BindOnce(&HandleSSLErrorWrapper), base::BindOnce(&IsInHostedApp)));
+ std::unique_ptr<security_interstitials::InsecureFormNavigationThrottle>
+ insecure_form_throttle = security_interstitials::
+ InsecureFormNavigationThrottle::MaybeCreateNavigationThrottle(
+ handle, std::make_unique<WebLayerSecurityBlockingPageFactory>(),
+ nullptr);
+ if (insecure_form_throttle) {
+ throttles.push_back(std::move(insecure_form_throttle));
+ }
+
#if defined(OS_ANDROID)
if (handle->IsInMainFrame()) {
if (base::FeatureList::IsEnabled(features::kWebLayerSafeBrowsing) &&
@@ -683,7 +778,7 @@ void ContentBrowserClientImpl::RenderProcessWillLaunch(
/*can_persist_data*/ true,
/*force_to_support_secure_codecs*/ false));
#endif
- TabSpecificContentSettingsDelegate::UpdateRendererContentSettingRules(host);
+ PageSpecificContentSettingsDelegate::UpdateRendererContentSettingRules(host);
}
scoped_refptr<content::QuotaPermissionContext>
@@ -691,12 +786,6 @@ ContentBrowserClientImpl::CreateQuotaPermissionContext() {
return base::MakeRefCounted<permissions::QuotaPermissionContextImpl>();
}
-content::TtsPlatform* ContentBrowserClientImpl::GetTtsPlatform() {
- // TODO(sky): figure out a better way to integrate this.
- content::TtsController::GetInstance()->SetStopSpeakingWhenHidden(true);
- return nullptr;
-}
-
void ContentBrowserClientImpl::CreateFeatureListAndFieldTrials() {
local_state_ = CreateLocalState();
feature_list_creator_ =
@@ -708,7 +797,7 @@ void ContentBrowserClientImpl::CreateFeatureListAndFieldTrials() {
#if defined(OS_ANDROID)
SafeBrowsingService* ContentBrowserClientImpl::GetSafeBrowsingService() {
- return BrowserProcess::GetInstance()->GetSafeBrowsingService(GetUserAgent());
+ return BrowserProcess::GetInstance()->GetSafeBrowsingService();
}
#endif
@@ -809,6 +898,12 @@ ContentBrowserClientImpl::CreateLoginDelegate(
auth_info, web_contents, first_auth_attempt,
std::move(auth_required_callback));
}
+
+std::unique_ptr<content::TtsEnvironmentAndroid>
+ContentBrowserClientImpl::CreateTtsEnvironmentAndroid() {
+ return std::make_unique<TtsEnvironmentAndroidImpl>();
+}
+
#endif // OS_ANDROID
content::SpeechRecognitionManagerDelegate*
diff --git a/chromium/weblayer/browser/content_browser_client_impl.h b/chromium/weblayer/browser/content_browser_client_impl.h
index a8c2ea7c804..881fa76274e 100644
--- a/chromium/weblayer/browser/content_browser_client_impl.h
+++ b/chromium/weblayer/browser/content_browser_client_impl.h
@@ -39,8 +39,6 @@ class ContentBrowserClientImpl : public content::ContentBrowserClient {
content::WebContents* web_contents) override;
bool CanShutdownGpuProcessNowOnIOThread() override;
content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
- base::Optional<service_manager::Manifest> GetServiceManifestOverlay(
- base::StringPiece name) override;
void LogWebFeatureForCurrentPage(content::RenderFrameHost* render_frame_host,
blink::mojom::WebFeature feature) override;
std::string GetProduct() override;
@@ -66,6 +64,10 @@ class ContentBrowserClientImpl : public content::ContentBrowserClient {
int frame_tree_node_id) override;
bool IsHandledURL(const GURL& url) override;
std::vector<url::Origin> GetOriginsRequiringDedicatedProcess() override;
+ bool MayReuseHost(content::RenderProcessHost* process_host) override;
+ void OverridePageVisibilityState(
+ content::RenderFrameHost* render_frame_host,
+ content::PageVisibilityState* visibility_state) override;
bool ShouldDisableSiteIsolation() override;
std::vector<std::string> GetAdditionalSiteIsolationModes() override;
void PersistIsolatedOrigin(content::BrowserContext* context,
@@ -130,11 +132,12 @@ class ContentBrowserClientImpl : public content::ContentBrowserClient {
scoped_refptr<net::HttpResponseHeaders> response_headers,
bool first_auth_attempt,
LoginAuthRequiredCallback auth_required_callback) override;
+ std::unique_ptr<content::TtsEnvironmentAndroid> CreateTtsEnvironmentAndroid()
+ override;
#endif // OS_ANDROID
content::SpeechRecognitionManagerDelegate*
CreateSpeechRecognitionManagerDelegate() override;
ukm::UkmService* GetUkmService() override;
- content::TtsPlatform* GetTtsPlatform() override;
void CreateFeatureListAndFieldTrials();
diff --git a/chromium/weblayer/browser/content_view_render_view.cc b/chromium/weblayer/browser/content_view_render_view.cc
index 98cd8bcf37a..1c97f4332db 100644
--- a/chromium/weblayer/browser/content_view_render_view.cc
+++ b/chromium/weblayer/browser/content_view_render_view.cc
@@ -83,13 +83,26 @@ void ContentViewRenderView::OnPhysicalBackingSizeChanged(
JNIEnv* env,
const JavaParamRef<jobject>& jweb_contents,
jint width,
- jint height) {
+ jint height,
+ jboolean for_config_change) {
bool height_changed = height_ != height;
height_ = height;
content::WebContents* web_contents =
content::WebContents::FromJavaWebContents(jweb_contents);
gfx::Size size(width, height);
- web_contents->GetNativeView()->OnPhysicalBackingSizeChanged(size);
+
+ // The default resize timeout on Android is 1s. It was chosen with browser
+ // use case in mind where resize is rare (eg orientation change, fullscreen)
+ // and users are generally willing to wait for those cases instead of seeing
+ // a frame at the wrong size. Weblayer currently can be resized while user
+ // is interacting with the page, in which case the timeout is too long.
+ // For now, use the default long timeout only for rotation (ie config change)
+ // and just use a zero timeout for all other cases.
+ base::Optional<base::TimeDelta> override_deadline;
+ if (!for_config_change)
+ override_deadline = base::TimeDelta();
+ web_contents->GetNativeView()->OnPhysicalBackingSizeChanged(
+ size, override_deadline);
if (height_changed && !height_changed_listener_.is_null())
height_changed_listener_.Run();
@@ -131,6 +144,13 @@ ContentViewRenderView::GetResourceManager(JNIEnv* env) {
return compositor_->GetResourceManager().GetJavaObject();
}
+void ContentViewRenderView::UpdateBackgroundColor(JNIEnv* env) {
+ if (!compositor_)
+ return;
+ compositor_->SetBackgroundColor(
+ Java_ContentViewRenderView_getBackgroundColor(env, java_obj_));
+}
+
void ContentViewRenderView::UpdateLayerTreeHost() {
// TODO(wkorman): Rename Layout to UpdateLayerTreeHost in all Android
// Compositor related classes.
@@ -166,6 +186,7 @@ void ContentViewRenderView::InitCompositor() {
cc::ElementId(root_container_layer_->id()));
root_container_layer_->SetIsDrawable(false);
compositor_->SetRootLayer(root_container_layer_);
+ UpdateBackgroundColor(base::android::AttachCurrentThread());
}
} // namespace weblayer
diff --git a/chromium/weblayer/browser/content_view_render_view.h b/chromium/weblayer/browser/content_view_render_view.h
index 3a28dac389f..0cf93c027d5 100644
--- a/chromium/weblayer/browser/content_view_render_view.h
+++ b/chromium/weblayer/browser/content_view_render_view.h
@@ -49,7 +49,8 @@ class ContentViewRenderView : public content::CompositorClient {
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jweb_contents,
jint width,
- jint height);
+ jint height,
+ jboolean for_config_change);
void SurfaceCreated(JNIEnv* env);
void SurfaceDestroyed(JNIEnv* env, jboolean cache_back_buffer);
void SurfaceChanged(JNIEnv* env,
@@ -61,6 +62,7 @@ class ContentViewRenderView : public content::CompositorClient {
void SetNeedsRedraw(JNIEnv* env);
void EvictCachedSurface(JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetResourceManager(JNIEnv* env);
+ void UpdateBackgroundColor(JNIEnv* env);
// CompositorClient implementation
void UpdateLayerTreeHost() override;
diff --git a/chromium/weblayer/browser/controls_visibility_reason.h b/chromium/weblayer/browser/controls_visibility_reason.h
index 7e6885f0681..e866f91ea01 100644
--- a/chromium/weblayer/browser/controls_visibility_reason.h
+++ b/chromium/weblayer/browser/controls_visibility_reason.h
@@ -28,6 +28,10 @@ enum class ControlsVisibilityReason {
// If accessibility is enabled, controls are forced shown.
kAccessibility,
+ // Browser controls visibility can be set to force them to animate in/out when
+ // being set or cleared.
+ kAnimation,
+
kReasonCount,
};
diff --git a/chromium/weblayer/browser/cookie_manager_impl.cc b/chromium/weblayer/browser/cookie_manager_impl.cc
index ae1392cb88e..4b5262e549f 100644
--- a/chromium/weblayer/browser/cookie_manager_impl.cc
+++ b/chromium/weblayer/browser/cookie_manager_impl.cc
@@ -147,9 +147,9 @@ bool CookieManagerImpl::SetCookieInternal(const GURL& url,
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetCookieManagerForBrowserProcess()
- ->SetCanonicalCookie(*cc, url, net::CookieOptions::MakeAllInclusive(),
- net::cookie_util::AdaptCookieInclusionStatusToBool(
- std::move(callback)));
+ ->SetCanonicalCookie(
+ *cc, url, net::CookieOptions::MakeAllInclusive(),
+ net::cookie_util::AdaptCookieAccessResultToBool(std::move(callback)));
return true;
}
diff --git a/chromium/weblayer/browser/default_search_engine.cc b/chromium/weblayer/browser/default_search_engine.cc
new file mode 100644
index 00000000000..756b43c3185
--- /dev/null
+++ b/chromium/weblayer/browser/default_search_engine.cc
@@ -0,0 +1,35 @@
+// Copyright 2020 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 "weblayer/browser/default_search_engine.h"
+
+#include "base/no_destructor.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "content/public/browser/browser_context.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+#include "weblayer/browser/host_content_settings_map_factory.h"
+
+namespace weblayer {
+
+const url::Origin& GetDseOrigin() {
+ static const base::NoDestructor<url::Origin> kOrigin(
+ url::Origin::Create(GURL("https://www.google.com")));
+ return *kOrigin;
+}
+
+bool IsPermissionControlledByDse(ContentSettingsType type,
+ const url::Origin& origin) {
+ return type == ContentSettingsType::GEOLOCATION && GetDseOrigin() == origin;
+}
+
+void ResetDsePermissions(content::BrowserContext* browser_context) {
+ GURL url = GetDseOrigin().GetURL();
+ HostContentSettingsMapFactory::GetForBrowserContext(browser_context)
+ ->SetContentSettingDefaultScope(url, url,
+ ContentSettingsType::GEOLOCATION,
+ std::string(), CONTENT_SETTING_ALLOW);
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/default_search_engine.h b/chromium/weblayer/browser/default_search_engine.h
new file mode 100644
index 00000000000..9ee6b45302e
--- /dev/null
+++ b/chromium/weblayer/browser/default_search_engine.h
@@ -0,0 +1,35 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_DEFAULT_SEARCH_ENGINE_H_
+#define WEBLAYER_BROWSER_DEFAULT_SEARCH_ENGINE_H_
+
+#include "components/content_settings/core/common/content_settings.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace url {
+class Origin;
+}
+
+namespace weblayer {
+const url::Origin& GetDseOrigin();
+
+// Returns whether permissions for |type| and |origin| are controlled by
+// WebLayer's default search engine logic. This only applies to the GEOLOCATION
+// permission, which will be force allowed and controlled by the client app's
+// system level location permissions.
+bool IsPermissionControlledByDse(ContentSettingsType type,
+ const url::Origin& origin);
+
+// Resets all permissions managed by WebLayer for the default search engine.
+// TODO(crbug.com/1063433): If this logic gets more complicated consider
+// refactoring SearchPermissionsService to be used in WebLayer.
+void ResetDsePermissions(content::BrowserContext* browser_context);
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_DEFAULT_SEARCH_ENGINE_H_
diff --git a/chromium/weblayer/browser/download_browsertest.cc b/chromium/weblayer/browser/download_browsertest.cc
index 15918ee9030..c44c8c89fa0 100644
--- a/chromium/weblayer/browser/download_browsertest.cc
+++ b/chromium/weblayer/browser/download_browsertest.cc
@@ -24,6 +24,7 @@
#include "weblayer/public/navigation_controller.h"
#include "weblayer/shell/browser/shell.h"
#include "weblayer/test/test_navigation_observer.h"
+#include "weblayer/test/weblayer_browser_test_utils.h"
namespace weblayer {
@@ -281,6 +282,13 @@ IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, Cancel) {
}
IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, PauseResume) {
+ // Add an initial navigation to avoid the tab being deleted if the first
+ // navigation is a download, since we use the tab for convenience in the
+ // lambda.
+ OneShotNavigationObserver observer(shell());
+ shell()->tab()->GetNavigationController()->Navigate(GURL("about:blank"));
+ observer.WaitForNavigation();
+
set_started_callback(base::BindLambdaForTesting([&](Download* download) {
download->Pause();
GURL url = embedded_test_server()->GetURL(
diff --git a/chromium/weblayer/browser/download_manager_delegate_impl.cc b/chromium/weblayer/browser/download_manager_delegate_impl.cc
index 00c35b6b4a7..1f889a95e92 100644
--- a/chromium/weblayer/browser/download_manager_delegate_impl.cc
+++ b/chromium/weblayer/browser/download_manager_delegate_impl.cc
@@ -209,6 +209,16 @@ void DownloadManagerDelegateImpl::OnManagerInitialized() {
void DownloadManagerDelegateImpl::OnDownloadUpdated(
download::DownloadItem* item) {
+ // If this is the first navigation in a tab it should be closed. Wait until
+ // the target path is determined or the download is canceled to check.
+ if (!item->GetTargetFilePath().empty() ||
+ item->GetState() == download::DownloadItem::CANCELLED) {
+ content::WebContents* web_contents =
+ content::DownloadItemUtils::GetWebContents(item);
+ if (web_contents && web_contents->GetController().IsInitialNavigation())
+ web_contents->Close();
+ }
+
auto* delegate = GetDelegate(item);
if (item->GetState() == download::DownloadItem::COMPLETE ||
item->GetState() == download::DownloadItem::CANCELLED ||
diff --git a/chromium/weblayer/browser/error_page_callback_proxy.cc b/chromium/weblayer/browser/error_page_callback_proxy.cc
index a823386788f..db7add323f3 100644
--- a/chromium/weblayer/browser/error_page_callback_proxy.cc
+++ b/chromium/weblayer/browser/error_page_callback_proxy.cc
@@ -4,8 +4,11 @@
#include "weblayer/browser/error_page_callback_proxy.h"
+#include "base/android/jni_string.h"
#include "url/gurl.h"
#include "weblayer/browser/java/jni/ErrorPageCallbackProxy_jni.h"
+#include "weblayer/browser/navigation_impl.h"
+#include "weblayer/public/error_page.h"
#include "weblayer/public/tab.h"
using base::android::AttachCurrentThread;
@@ -29,6 +32,19 @@ bool ErrorPageCallbackProxy::OnBackToSafety() {
return Java_ErrorPageCallbackProxy_onBackToSafety(env, java_impl_);
}
+std::unique_ptr<ErrorPage> ErrorPageCallbackProxy::GetErrorPageContent(
+ Navigation* navigation) {
+ JNIEnv* env = AttachCurrentThread();
+ auto error_string = Java_ErrorPageCallbackProxy_getErrorPageContent(
+ env, java_impl_,
+ static_cast<NavigationImpl*>(navigation)->java_navigation());
+ if (!error_string)
+ return nullptr;
+ auto error_page = std::make_unique<ErrorPage>();
+ error_page->html = ConvertJavaStringToUTF8(env, error_string);
+ return error_page;
+}
+
static jlong JNI_ErrorPageCallbackProxy_CreateErrorPageCallbackProxy(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& proxy,
diff --git a/chromium/weblayer/browser/error_page_callback_proxy.h b/chromium/weblayer/browser/error_page_callback_proxy.h
index a63fcc2b157..ad005842f9e 100644
--- a/chromium/weblayer/browser/error_page_callback_proxy.h
+++ b/chromium/weblayer/browser/error_page_callback_proxy.h
@@ -24,6 +24,8 @@ class ErrorPageCallbackProxy : public ErrorPageDelegate {
// ErrorPageDelegate:
bool OnBackToSafety() override;
+ std::unique_ptr<ErrorPage> GetErrorPageContent(
+ Navigation* navigation) override;
private:
Tab* tab_;
diff --git a/chromium/weblayer/browser/errorpage_browsertest.cc b/chromium/weblayer/browser/errorpage_browsertest.cc
index ea080df71f0..776b26ba143 100644
--- a/chromium/weblayer/browser/errorpage_browsertest.cc
+++ b/chromium/weblayer/browser/errorpage_browsertest.cc
@@ -7,10 +7,13 @@
#include "base/macros.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h"
+#include "components/error_page/content/browser/net_error_auto_reloader.h"
+#include "content/public/test/browser_test_utils.h"
#include "content/public/test/url_loader_interceptor.h"
-#include "net/base/mock_network_change_notifier.h"
#include "net/test/url_request/url_request_failed_job.h"
-#include "weblayer/common/features.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/public/common/switches.h"
+#include "weblayer/public/navigation_controller.h"
#include "weblayer/shell/browser/shell.h"
#include "weblayer/test/weblayer_browser_test_utils.h"
@@ -49,8 +52,49 @@ IN_PROC_BROWSER_TEST_F(ErrorPageBrowserTest, 404WithEmptyBody) {
class ErrorPageReloadBrowserTest : public ErrorPageBrowserTest {
public:
- ErrorPageReloadBrowserTest() {
- feature_list_.InitAndEnableFeature(features::kEnableAutoReload);
+ ErrorPageReloadBrowserTest() = default;
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kEnableAutoReload);
+ ErrorPageBrowserTest::SetUpCommandLine(command_line);
+ }
+
+ // Helper to perform navigations, whether successful or intercepted for
+ // simulated failure. Note that this asynchronously initiates the navigation
+ // and then waits only for the *navigation* to finish; this is in contrast to
+ // common test utilities which wait for loading to finish. It matters because
+ // most of NetErrorAutoReloader's interesting behavior is triggered at
+ // navigation completion and tests may want to observe the immediate side
+ // effects, such as the scheduling of an auto-reload timer.
+ //
+ // Return true if the navigation was successful, or false if it failed.
+ bool Navigate(const GURL& url, bool disable_network_error_auto_reload = false)
+ WARN_UNUSED_RESULT {
+ content::TestNavigationManager navigation(web_contents(), url);
+ NavigationController::NavigateParams params;
+ params.disable_network_error_auto_reload =
+ disable_network_error_auto_reload;
+ shell()->tab()->GetNavigationController()->Navigate(url, params);
+ navigation.WaitForNavigationFinished();
+ return navigation.was_successful();
+ }
+
+ // Returns the time-delay of the currently scheduled auto-reload task, if one
+ // is scheduled. If no auto-reload is scheduled, this returns null.
+ base::Optional<base::TimeDelta> GetCurrentAutoReloadDelay() {
+ auto* auto_reloader =
+ error_page::NetErrorAutoReloader::FromWebContents(web_contents());
+ if (!auto_reloader)
+ return base::nullopt;
+ const base::Optional<base::OneShotTimer>& timer =
+ auto_reloader->next_reload_timer_for_testing();
+ if (!timer)
+ return base::nullopt;
+ return timer->GetCurrentDelay();
+ }
+
+ content::WebContents* web_contents() {
+ return static_cast<TabImpl*>(shell()->tab())->web_contents();
}
private:
@@ -58,13 +102,15 @@ class ErrorPageReloadBrowserTest : public ErrorPageBrowserTest {
};
IN_PROC_BROWSER_TEST_F(ErrorPageReloadBrowserTest, ReloadOnNetworkChanged) {
- // Make sure the renderer thinks it's online, since that is a necessary
- // condition for the reload.
- net::test::ScopedMockNetworkChangeNotifier mock_network_change_notifier;
- mock_network_change_notifier.mock_network_change_notifier()
- ->SetConnectionType(net::NetworkChangeNotifier::CONNECTION_4G);
-
ASSERT_TRUE(embedded_test_server()->Start());
+ // Ensure that the NetErrorAutoReloader believes it's online, otherwise it
+ // does not attempt auto-reload on error pages.
+ error_page::NetErrorAutoReloader::CreateForWebContents(web_contents());
+ auto* reloader =
+ error_page::NetErrorAutoReloader::FromWebContents(web_contents());
+ reloader->DisableConnectionChangeObservationForTesting();
+ reloader->OnConnectionChanged(network::mojom::ConnectionType::CONNECTION_4G);
+
GURL url = embedded_test_server()->GetURL("/error_page");
// We send net::ERR_NETWORK_CHANGED on the first load, and the reload should
// get a net::OK response.
@@ -88,4 +134,48 @@ IN_PROC_BROWSER_TEST_F(ErrorPageReloadBrowserTest, ReloadOnNetworkChanged) {
NavigateAndWaitForCompletion(url, shell());
}
+// By default auto reload is enabled.
+IN_PROC_BROWSER_TEST_F(ErrorPageReloadBrowserTest, AutoReloadDefault) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ // Ensure that the NetErrorAutoReloader believes it's online, otherwise it
+ // does not attempt auto-reload on error pages.
+ error_page::NetErrorAutoReloader::CreateForWebContents(web_contents());
+ auto* reloader =
+ error_page::NetErrorAutoReloader::FromWebContents(web_contents());
+ reloader->DisableConnectionChangeObservationForTesting();
+ reloader->OnConnectionChanged(network::mojom::ConnectionType::CONNECTION_4G);
+
+ GURL url = embedded_test_server()->GetURL("/error_page");
+ content::URLLoaderInterceptor interceptor(base::BindLambdaForTesting(
+ [&url](content::URLLoaderInterceptor::RequestParams* params) {
+ if (params->url_request.url == url) {
+ params->client->OnComplete(
+ network::URLLoaderCompletionStatus(net::ERR_NETWORK_CHANGED));
+ return true;
+ }
+ return false;
+ }));
+
+ EXPECT_FALSE(Navigate(url));
+ EXPECT_EQ(error_page::NetErrorAutoReloader::GetNextReloadDelayForTesting(0),
+ GetCurrentAutoReloadDelay());
+}
+
+IN_PROC_BROWSER_TEST_F(ErrorPageReloadBrowserTest, AutoReloadDisabled) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ GURL url = embedded_test_server()->GetURL("/error_page");
+ content::URLLoaderInterceptor interceptor(base::BindLambdaForTesting(
+ [&url](content::URLLoaderInterceptor::RequestParams* params) {
+ if (params->url_request.url == url) {
+ params->client->OnComplete(
+ network::URLLoaderCompletionStatus(net::ERR_NETWORK_CHANGED));
+ return true;
+ }
+ return false;
+ }));
+
+ EXPECT_FALSE(Navigate(url, true));
+ EXPECT_EQ(base::nullopt, GetCurrentAutoReloadDelay());
+}
+
} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/favicon_backend_wrapper.cc b/chromium/weblayer/browser/favicon/favicon_backend_wrapper.cc
new file mode 100644
index 00000000000..9f3108b7495
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_backend_wrapper.cc
@@ -0,0 +1,193 @@
+// Copyright 2020 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 "weblayer/browser/favicon/favicon_backend_wrapper.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/sequenced_task_runner.h"
+#include "components/favicon/core/favicon_backend.h"
+#include "components/favicon/core/favicon_database.h"
+
+namespace weblayer {
+
+// Removing out of date entries can be costly. To avoid blocking the thread
+// this code runs on, the work is potentially throttled. Specifically at
+// most |kMaxNumberOfEntriesToRemoveAtATime| are removed during a single call.
+// If |kMaxNumberOfEntriesToRemoveAtATime| are removed, then there may be more
+// entries that can be removed, so the timer is restarted with a shorter time
+// out (|kTimeDeltaForRunningExpireWithRemainingWork|).
+constexpr base::TimeDelta kTimeDeltaForRunningExpireNoRemainingWork =
+ base::TimeDelta::FromHours(1);
+constexpr int kMaxNumberOfEntriesToRemoveAtATime = 100;
+
+FaviconBackendWrapper::FaviconBackendWrapper(
+ scoped_refptr<base::SequencedTaskRunner> task_runner)
+ : base::RefCountedDeleteOnSequence<FaviconBackendWrapper>(task_runner),
+ task_runner_(task_runner) {}
+
+void FaviconBackendWrapper::Init(const base::FilePath& db_path) {
+ db_path_ = db_path;
+ favicon_backend_ = favicon::FaviconBackend::Create(db_path, this);
+ if (!favicon_backend_) {
+ LOG(WARNING) << "Could not initialize the favicon database.";
+
+ // The favicon db is not critical. On failure initializing try deleting
+ // the file and repeating. Note that FaviconDatabase already tries to
+ // initialize twice.
+ base::DeleteFile(db_path);
+
+ favicon_backend_ = favicon::FaviconBackend::Create(db_path, this);
+ if (!favicon_backend_) {
+ LOG(WARNING) << "Could not initialize db second time, giving up.";
+ return;
+ }
+ }
+
+ expire_timer_.Start(FROM_HERE, kTimeDeltaForRunningExpireWithRemainingWork,
+ this, &FaviconBackendWrapper::OnExpireTimerFired);
+}
+
+void FaviconBackendWrapper::Shutdown() {
+ // Ensures there isn't a reference to this in the task runner (by way of the
+ // task the timer posts).
+ commit_timer_.Stop();
+ expire_timer_.Stop();
+}
+
+void FaviconBackendWrapper::DeleteAndRecreateDatabase() {
+ Shutdown();
+ favicon_backend_.reset();
+ base::DeleteFile(db_path_);
+ Init(db_path_);
+}
+
+std::vector<favicon_base::FaviconRawBitmapResult>
+FaviconBackendWrapper::GetFaviconsForUrl(
+ const GURL& page_url,
+ const favicon_base::IconTypeSet& icon_types,
+ const std::vector<int>& desired_sizes) {
+ if (!favicon_backend_)
+ return {};
+ return favicon_backend_->GetFaviconsForUrl(page_url, icon_types,
+ desired_sizes,
+ /* fallback_to_host */ false);
+}
+
+void FaviconBackendWrapper::SetFaviconsOutOfDateForPage(const GURL& page_url) {
+ if (favicon_backend_ &&
+ favicon_backend_->SetFaviconsOutOfDateForPage(page_url)) {
+ ScheduleCommit();
+ }
+}
+
+void FaviconBackendWrapper::SetFavicons(const base::flat_set<GURL>& page_urls,
+ favicon_base::IconType icon_type,
+ const GURL& icon_url,
+ const std::vector<SkBitmap>& bitmaps) {
+ if (favicon_backend_ &&
+ favicon_backend_
+ ->SetFavicons(page_urls, icon_type, icon_url, bitmaps,
+ favicon::FaviconBitmapType::ON_VISIT)
+ .did_change_database()) {
+ ScheduleCommit();
+ }
+}
+
+void FaviconBackendWrapper::CloneFaviconMappingsForPages(
+ const GURL& page_url_to_read,
+ const favicon_base::IconTypeSet& icon_types,
+ const base::flat_set<GURL>& page_urls_to_write) {
+ if (!favicon_backend_)
+ return;
+
+ std::set<GURL> changed_urls = favicon_backend_->CloneFaviconMappingsForPages(
+ {page_url_to_read}, icon_types, page_urls_to_write);
+ if (!changed_urls.empty())
+ ScheduleCommit();
+}
+
+std::vector<favicon_base::FaviconRawBitmapResult>
+FaviconBackendWrapper::GetFavicon(const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const std::vector<int>& desired_sizes) {
+ return UpdateFaviconMappingsAndFetch({}, icon_url, icon_type, desired_sizes);
+}
+
+std::vector<favicon_base::FaviconRawBitmapResult>
+FaviconBackendWrapper::UpdateFaviconMappingsAndFetch(
+ const base::flat_set<GURL>& page_urls,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const std::vector<int>& desired_sizes) {
+ if (!favicon_backend_)
+ return {};
+ auto result = favicon_backend_->UpdateFaviconMappingsAndFetch(
+ page_urls, icon_url, icon_type, desired_sizes);
+ if (!result.updated_page_urls.empty())
+ ScheduleCommit();
+ return result.bitmap_results;
+}
+
+void FaviconBackendWrapper::DeleteFaviconMappings(
+ const base::flat_set<GURL>& page_urls,
+ favicon_base::IconType icon_type) {
+ if (!favicon_backend_)
+ return;
+
+ auto deleted_page_urls =
+ favicon_backend_->DeleteFaviconMappings(page_urls, icon_type);
+ if (!deleted_page_urls.empty())
+ ScheduleCommit();
+}
+
+std::vector<GURL> FaviconBackendWrapper::GetCachedRecentRedirectsForPage(
+ const GURL& page_url) {
+ // By only returning |page_url| this code won't set the favicon on redirects.
+ // If that becomes necessary, we would need this class to know about
+ // redirects. Chrome does this by way of HistoryService remembering redirects
+ // for recent pages. See |HistoryBackend::recent_redirects_|.
+ return {page_url};
+}
+
+FaviconBackendWrapper::~FaviconBackendWrapper() = default;
+
+void FaviconBackendWrapper::ScheduleCommit() {
+ if (!commit_timer_.IsRunning()) {
+ // 10 seconds matches that of HistoryBackend.
+ commit_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(10), this,
+ &FaviconBackendWrapper::Commit);
+ }
+}
+
+void FaviconBackendWrapper::Commit() {
+ if (favicon_backend_)
+ favicon_backend_->Commit();
+}
+
+void FaviconBackendWrapper::OnExpireTimerFired() {
+ if (!favicon_backend_)
+ return;
+
+ // See comments above |kTimeDeltaForRunningExpireNoRemainingWork| for a
+ // description of this logic.
+ favicon::FaviconDatabase* db = favicon_backend_->db();
+ auto icon_ids = db->GetFaviconsLastUpdatedBefore(
+ base::Time::Now() - kTimeDeltaWhenEntriesAreRemoved,
+ kMaxNumberOfEntriesToRemoveAtATime);
+ for (favicon_base::FaviconID icon_id : icon_ids) {
+ db->DeleteFavicon(icon_id);
+ db->DeleteIconMappingsForFaviconId(icon_id);
+ }
+ if (!icon_ids.empty())
+ Commit();
+ const base::TimeDelta delta =
+ icon_ids.size() == kMaxNumberOfEntriesToRemoveAtATime
+ ? kTimeDeltaForRunningExpireWithRemainingWork
+ : kTimeDeltaForRunningExpireNoRemainingWork;
+ expire_timer_.Start(FROM_HERE, delta, this,
+ &FaviconBackendWrapper::OnExpireTimerFired);
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/favicon_backend_wrapper.h b/chromium/weblayer/browser/favicon/favicon_backend_wrapper.h
new file mode 100644
index 00000000000..eb74c63ca03
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_backend_wrapper.h
@@ -0,0 +1,122 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_FAVICON_FAVICON_BACKEND_WRAPPER_H_
+#define WEBLAYER_BROWSER_FAVICON_FAVICON_BACKEND_WRAPPER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_delete_on_sequence.h"
+#include "base/timer/timer.h"
+#include "components/favicon/core/favicon_backend_delegate.h"
+#include "components/favicon_base/favicon_types.h"
+
+class GURL;
+
+namespace base {
+class FilePath;
+class SequencedTaskRunner;
+} // namespace base
+
+namespace favicon {
+class FaviconBackend;
+}
+
+namespace weblayer {
+
+// FaviconBackendWrapper runs on a background task-runner and owns the database
+// side of favicons. This class largely delegates to favicon::FaviconBackend.
+class FaviconBackendWrapper
+ : public base::RefCountedDeleteOnSequence<FaviconBackendWrapper>,
+ public favicon::FaviconBackendDelegate {
+ public:
+ explicit FaviconBackendWrapper(
+ scoped_refptr<base::SequencedTaskRunner> task_runner);
+ FaviconBackendWrapper(const FaviconBackendWrapper&) = delete;
+ FaviconBackendWrapper& operator=(const FaviconBackendWrapper&) = delete;
+
+ void Init(const base::FilePath& db_path);
+
+ void Shutdown();
+
+ void DeleteAndRecreateDatabase();
+
+ // All of these functions are called by the FaviconServiceImpl. They call
+ // through to |favicon_backend_|.
+ std::vector<favicon_base::FaviconRawBitmapResult> GetFaviconsForUrl(
+ const GURL& page_url,
+ const favicon_base::IconTypeSet& icon_types,
+ const std::vector<int>& desired_sizes);
+ void SetFaviconsOutOfDateForPage(const GURL& page_url);
+ void SetFavicons(const base::flat_set<GURL>& page_urls,
+ favicon_base::IconType icon_type,
+ const GURL& icon_url,
+ const std::vector<SkBitmap>& bitmaps);
+ void CloneFaviconMappingsForPages(
+ const GURL& page_url_to_read,
+ const favicon_base::IconTypeSet& icon_types,
+ const base::flat_set<GURL>& page_urls_to_write);
+ std::vector<favicon_base::FaviconRawBitmapResult> GetFavicon(
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const std::vector<int>& desired_sizes);
+ std::vector<favicon_base::FaviconRawBitmapResult>
+ UpdateFaviconMappingsAndFetch(const base::flat_set<GURL>& page_urls,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const std::vector<int>& desired_sizes);
+ void DeleteFaviconMappings(const base::flat_set<GURL>& page_urls,
+ favicon_base::IconType icon_type);
+
+ // favicon::FaviconBackendDelegate:
+ std::vector<GURL> GetCachedRecentRedirectsForPage(
+ const GURL& page_url) override;
+
+ private:
+ friend class base::RefCountedDeleteOnSequence<FaviconBackendWrapper>;
+ friend class base::DeleteHelper<FaviconBackendWrapper>;
+ friend class FaviconBackendWrapperTest;
+
+ ~FaviconBackendWrapper() override;
+
+ void ScheduleCommit();
+ void Commit();
+
+ // Called to expire (remove) out of date icons and restart the timer.
+ void OnExpireTimerFired();
+
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ // Timer used to delay commits for a short amount of time. This done to
+ // batch commits.
+ base::OneShotTimer commit_timer_;
+
+ // The real implementation of the backend. Is there is a problem initializing
+ // the database this will be null.
+ std::unique_ptr<favicon::FaviconBackend> favicon_backend_;
+
+ // Timer used to remove items from the database that are likely no longer
+ // needed.
+ base::OneShotTimer expire_timer_;
+
+ base::FilePath db_path_;
+};
+
+// These values are here only for tests.
+
+// Amount of time before favicons are removed. That is, any favicons downloaded
+// before this amount of time are removed.
+constexpr base::TimeDelta kTimeDeltaWhenEntriesAreRemoved =
+ base::TimeDelta::FromDays(30);
+
+// See comment near kMaxNumberOfEntriesToRemoveAtATime for details on this.
+constexpr base::TimeDelta kTimeDeltaForRunningExpireWithRemainingWork =
+ base::TimeDelta::FromMinutes(2);
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_FAVICON_FAVICON_BACKEND_WRAPPER_H_
diff --git a/chromium/weblayer/browser/favicon/favicon_backend_wrapper_unittest.cc b/chromium/weblayer/browser/favicon/favicon_backend_wrapper_unittest.cc
new file mode 100644
index 00000000000..517b68426d8
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_backend_wrapper_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2020 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 "weblayer/browser/favicon/favicon_backend_wrapper.h"
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/favicon/core/favicon_backend.h"
+#include "components/favicon/core/favicon_database.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace weblayer {
+namespace {
+
+// Blobs for adding favicons.
+const unsigned char kBlob1[] =
+ "12346102356120394751634516591348710478123649165419234519234512349134";
+
+} // namespace
+
+class FaviconBackendWrapperTest : public testing::Test {
+ protected:
+ favicon::FaviconBackend* backend() {
+ return wrapper_->favicon_backend_.get();
+ }
+
+ // testing::Test:
+ void SetUp() override {
+ // Get a temporary directory for the test DB files.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ db_path_ = temp_dir_.GetPath().AppendASCII("test_db");
+ }
+
+ void TearDown() override {
+ wrapper_ = nullptr;
+ testing::Test::TearDown();
+ }
+
+ base::test::SingleThreadTaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+ base::ScopedTempDir temp_dir_;
+ base::FilePath db_path_;
+ scoped_refptr<FaviconBackendWrapper> wrapper_;
+};
+
+TEST_F(FaviconBackendWrapperTest, BasicExpire) {
+ wrapper_ = base::MakeRefCounted<FaviconBackendWrapper>(
+ base::ThreadTaskRunnerHandle::Get());
+ wrapper_->Init(db_path_);
+ ASSERT_TRUE(backend());
+ auto* db = backend()->db();
+
+ std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+ scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+ GURL url("http://google.com");
+ const base::Time time1 = base::Time::Now();
+ favicon_base::FaviconID favicon_id1 =
+ db->AddFavicon(url, favicon_base::IconType::kTouchIcon, favicon,
+ favicon::FaviconBitmapType::ON_VISIT, time1, gfx::Size());
+ ASSERT_NE(0, favicon_id1);
+ favicon::IconMappingID icon_mapping_id1 =
+ db->AddIconMapping(url, favicon_id1);
+ ASSERT_NE(0, icon_mapping_id1);
+
+ // Fast forward past first expire running.
+ task_environment_.FastForwardBy(kTimeDeltaForRunningExpireWithRemainingWork *
+ 2);
+ // The icon should still be there.
+ EXPECT_TRUE(db->GetFaviconHeader(favicon_id1, nullptr, nullptr));
+ EXPECT_TRUE(db->HasMappingFor(favicon_id1));
+
+ // Fast forward such that the icon is removed.
+ task_environment_.FastForwardBy(kTimeDeltaWhenEntriesAreRemoved);
+ EXPECT_FALSE(db->GetFaviconHeader(favicon_id1, nullptr, nullptr));
+ EXPECT_FALSE(db->HasMappingFor(favicon_id1));
+}
+
+TEST_F(FaviconBackendWrapperTest, ExpireWithOneRemaining) {
+ wrapper_ = base::MakeRefCounted<FaviconBackendWrapper>(
+ base::ThreadTaskRunnerHandle::Get());
+ wrapper_->Init(db_path_);
+ ASSERT_TRUE(backend());
+ auto* db = backend()->db();
+
+ // Add two entries. The second is more recent then the first.
+ std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+ scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+ GURL url("http://google.com");
+ const base::Time time1 = base::Time::Now();
+ favicon_base::FaviconID favicon_id1 =
+ db->AddFavicon(url, favicon_base::IconType::kTouchIcon, favicon,
+ favicon::FaviconBitmapType::ON_VISIT, time1, gfx::Size());
+ ASSERT_NE(0, favicon_id1);
+ favicon::IconMappingID icon_mapping_id1 =
+ db->AddIconMapping(url, favicon_id1);
+ ASSERT_NE(0, icon_mapping_id1);
+ const base::Time time2 = time1 + kTimeDeltaWhenEntriesAreRemoved / 2;
+ favicon_base::FaviconID favicon_id2 =
+ db->AddFavicon(url, favicon_base::IconType::kTouchIcon, favicon,
+ favicon::FaviconBitmapType::ON_VISIT, time2, gfx::Size());
+ ASSERT_NE(0, favicon_id2);
+ favicon::IconMappingID icon_mapping_id2 =
+ db->AddIconMapping(url, favicon_id2);
+ ASSERT_NE(0, icon_mapping_id2);
+
+ // Fast forward such the first entry is expired and should be removed, but
+ // not the second.
+ task_environment_.FastForwardBy(kTimeDeltaWhenEntriesAreRemoved +
+ base::TimeDelta::FromDays(1));
+ EXPECT_FALSE(db->GetFaviconHeader(favicon_id1, nullptr, nullptr));
+ EXPECT_FALSE(db->HasMappingFor(favicon_id1));
+ EXPECT_TRUE(db->GetFaviconHeader(favicon_id2, nullptr, nullptr));
+ EXPECT_TRUE(db->HasMappingFor(favicon_id2));
+
+ // Fast forward enough such that second is removed.
+ task_environment_.FastForwardBy(kTimeDeltaWhenEntriesAreRemoved +
+ base::TimeDelta::FromDays(1));
+ EXPECT_FALSE(db->GetFaviconHeader(favicon_id2, nullptr, nullptr));
+ EXPECT_FALSE(db->HasMappingFor(favicon_id2));
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/favicon_callback_proxy.cc b/chromium/weblayer/browser/favicon/favicon_callback_proxy.cc
new file mode 100644
index 00000000000..4ec3a90edf3
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_callback_proxy.cc
@@ -0,0 +1,45 @@
+// Copyright 2020 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 "weblayer/browser/favicon/favicon_callback_proxy.h"
+
+#include "base/android/jni_string.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+#include "url/gurl.h"
+#include "weblayer/browser/java/jni/FaviconCallbackProxy_jni.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/public/favicon_fetcher.h"
+
+namespace weblayer {
+
+FaviconCallbackProxy::FaviconCallbackProxy(JNIEnv* env, jobject obj, Tab* tab)
+ : java_proxy_(env, obj),
+ favicon_fetcher_(tab->CreateFaviconFetcher(this)) {}
+
+FaviconCallbackProxy::~FaviconCallbackProxy() = default;
+
+void FaviconCallbackProxy::OnFaviconChanged(const gfx::Image& image) {
+ SkBitmap favicon = image.AsImageSkia().GetRepresentation(1.0f).GetBitmap();
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_FaviconCallbackProxy_onFaviconChanged(
+ env, java_proxy_,
+ favicon.empty() ? nullptr : gfx::ConvertToJavaBitmap(&favicon));
+}
+
+static jlong JNI_FaviconCallbackProxy_CreateFaviconCallbackProxy(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& proxy,
+ jlong tab) {
+ return reinterpret_cast<jlong>(
+ new FaviconCallbackProxy(env, proxy, reinterpret_cast<TabImpl*>(tab)));
+}
+
+static void JNI_FaviconCallbackProxy_DeleteFaviconCallbackProxy(JNIEnv* env,
+ jlong proxy) {
+ delete reinterpret_cast<FaviconCallbackProxy*>(proxy);
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/favicon_callback_proxy.h b/chromium/weblayer/browser/favicon/favicon_callback_proxy.h
new file mode 100644
index 00000000000..a15bc12bf75
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_callback_proxy.h
@@ -0,0 +1,39 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_FAVICON_FAVICON_CALLBACK_PROXY_H_
+#define WEBLAYER_BROWSER_FAVICON_FAVICON_CALLBACK_PROXY_H_
+
+#include <memory>
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "weblayer/public/favicon_fetcher_delegate.h"
+
+namespace weblayer {
+
+class FaviconFetcher;
+class Tab;
+
+// FullscreenCallbackProxy forwards all FullscreenDelegate functions to the
+// Java side. There is at most one FullscreenCallbackProxy per Tab.
+class FaviconCallbackProxy : public FaviconFetcherDelegate {
+ public:
+ FaviconCallbackProxy(JNIEnv* env, jobject obj, Tab* tab);
+ FaviconCallbackProxy(const FaviconCallbackProxy&) = delete;
+ FaviconCallbackProxy& operator=(const FaviconCallbackProxy&) = delete;
+ ~FaviconCallbackProxy() override;
+
+ // FaviconFetcherDelegate:
+ void OnFaviconChanged(const gfx::Image& image) override;
+
+ private:
+ base::android::ScopedJavaGlobalRef<jobject> java_proxy_;
+ std::unique_ptr<FaviconFetcher> favicon_fetcher_;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_FAVICON_FAVICON_CALLBACK_PROXY_H_
diff --git a/chromium/weblayer/browser/favicon/favicon_fetcher_browsertest.cc b/chromium/weblayer/browser/favicon/favicon_fetcher_browsertest.cc
new file mode 100644
index 00000000000..b5231214816
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_fetcher_browsertest.cc
@@ -0,0 +1,167 @@
+// Copyright 2020 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 "weblayer/browser/favicon/favicon_fetcher_impl.h"
+
+#include "base/run_loop.h"
+#include "build/build_config.h"
+#include "components/favicon/content/content_favicon_driver.h"
+#include "ui/gfx/image/image.h"
+#include "weblayer/browser/browser_context_impl.h"
+#include "weblayer/browser/favicon/favicon_fetcher_impl.h"
+#include "weblayer/browser/favicon/favicon_service_impl.h"
+#include "weblayer/browser/favicon/favicon_service_impl_factory.h"
+#include "weblayer/browser/favicon/favicon_service_impl_observer.h"
+#include "weblayer/browser/favicon/test_favicon_fetcher_delegate.h"
+#include "weblayer/browser/profile_impl.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/public/browser.h"
+#include "weblayer/public/favicon_fetcher_delegate.h"
+#include "weblayer/public/navigation_controller.h"
+#include "weblayer/shell/browser/shell.h"
+#include "weblayer/test/test_navigation_observer.h"
+#include "weblayer/test/weblayer_browser_test.h"
+#include "weblayer/test/weblayer_browser_test_utils.h"
+
+namespace weblayer {
+namespace {
+
+// FaviconServiceImplObserver used to wait for download to fail.
+class TestFaviconServiceImplObserver : public FaviconServiceImplObserver {
+ public:
+ void Wait() {
+ ASSERT_EQ(nullptr, run_loop_.get());
+ run_loop_ = std::make_unique<base::RunLoop>();
+ run_loop_->Run();
+ run_loop_.reset();
+ }
+
+ // FaviconServiceImplObserver:
+ void OnUnableToDownloadFavicon() override {
+ if (run_loop_)
+ run_loop_->Quit();
+ }
+
+ private:
+ std::unique_ptr<base::RunLoop> run_loop_;
+};
+
+} // namespace
+
+using FaviconFetcherBrowserTest = WebLayerBrowserTest;
+
+IN_PROC_BROWSER_TEST_F(FaviconFetcherBrowserTest, Basic) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ TestFaviconFetcherDelegate fetcher_delegate;
+ auto fetcher = shell()->tab()->CreateFaviconFetcher(&fetcher_delegate);
+ NavigateAndWaitForCompletion(
+ embedded_test_server()->GetURL("/simple_page_with_favicon.html"),
+ shell());
+ fetcher_delegate.WaitForFavicon();
+ EXPECT_FALSE(fetcher_delegate.last_image().IsEmpty());
+ EXPECT_EQ(fetcher_delegate.last_image(), fetcher->GetFavicon());
+ EXPECT_EQ(1, fetcher_delegate.on_favicon_changed_call_count());
+ fetcher_delegate.ClearLastImage();
+
+ const GURL url2 =
+ embedded_test_server()->GetURL("/simple_page_with_favicon2.html");
+ shell()->tab()->GetNavigationController()->Navigate(url2);
+ // Favicon doesn't change immediately on navigation.
+ EXPECT_FALSE(fetcher->GetFavicon().IsEmpty());
+ // Favicon does change once start is received.
+ TestNavigationObserver test_observer(
+ url2, TestNavigationObserver::NavigationEvent::kStart, shell());
+ test_observer.Wait();
+ EXPECT_TRUE(fetcher_delegate.last_image().IsEmpty());
+
+ fetcher_delegate.WaitForNonemptyFavicon();
+ EXPECT_FALSE(fetcher_delegate.last_image().IsEmpty());
+ EXPECT_EQ(fetcher_delegate.last_image(), fetcher->GetFavicon());
+ // OnFaviconChanged() is called twice, once with an empty image (because of
+ // the navigation), the second with the real image.
+ EXPECT_EQ(2, fetcher_delegate.on_favicon_changed_call_count());
+}
+
+IN_PROC_BROWSER_TEST_F(FaviconFetcherBrowserTest, NavigateToPageWithNoFavicon) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ TestFaviconFetcherDelegate fetcher_delegate;
+ auto fetcher = shell()->tab()->CreateFaviconFetcher(&fetcher_delegate);
+ NavigateAndWaitForCompletion(
+ embedded_test_server()->GetURL("/simple_page_with_favicon.html"),
+ shell());
+ fetcher_delegate.WaitForFavicon();
+ fetcher_delegate.ClearLastImage();
+
+ TestFaviconServiceImplObserver test_observer;
+ FaviconServiceImplFactory::GetForBrowserContext(
+ static_cast<TabImpl*>(shell()->tab())->profile()->GetBrowserContext())
+ ->set_observer(&test_observer);
+
+ const GURL url2 = embedded_test_server()->GetURL("/simple_page.html");
+ shell()->tab()->GetNavigationController()->Navigate(url2);
+ EXPECT_TRUE(fetcher_delegate.last_image().IsEmpty());
+ // The delegate should be notified of the empty image once.
+ test_observer.Wait();
+ EXPECT_TRUE(fetcher_delegate.last_image().IsEmpty());
+ EXPECT_EQ(1, fetcher_delegate.on_favicon_changed_call_count());
+}
+
+IN_PROC_BROWSER_TEST_F(FaviconFetcherBrowserTest,
+ ContentFaviconDriverLifetime) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ content::WebContents* web_contents =
+ static_cast<TabImpl*>(shell()->tab())->web_contents();
+
+ // Initially there should be no driver (because favicons haven't been
+ // requested).
+ EXPECT_EQ(nullptr,
+ favicon::ContentFaviconDriver::FromWebContents(web_contents));
+
+ // Request a fetcher, which should trigger creating ContentFaviconDriver.
+ TestFaviconFetcherDelegate fetcher_delegate;
+ auto fetcher = shell()->tab()->CreateFaviconFetcher(&fetcher_delegate);
+ EXPECT_NE(nullptr,
+ favicon::ContentFaviconDriver::FromWebContents(web_contents));
+
+ // Destroy the fetcher, which should destroy ContentFaviconDriver.
+ fetcher.reset();
+ EXPECT_EQ(nullptr,
+ favicon::ContentFaviconDriver::FromWebContents(web_contents));
+
+ // One more time, and this time navigate.
+ fetcher = shell()->tab()->CreateFaviconFetcher(&fetcher_delegate);
+ NavigateAndWaitForCompletion(
+ embedded_test_server()->GetURL("/simple_page_with_favicon.html"),
+ shell());
+ fetcher_delegate.WaitForFavicon();
+ EXPECT_FALSE(fetcher_delegate.last_image().IsEmpty());
+}
+
+// This test creates a Browser and Tab, which doesn't work well with Java when
+// driven from native code.
+#if !defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(FaviconFetcherBrowserTest, OffTheRecord) {
+ auto otr_profile = Profile::Create(std::string());
+ ProfileImpl* otr_profile_impl = static_cast<ProfileImpl*>(otr_profile.get());
+ EXPECT_TRUE(otr_profile_impl->GetBrowserContext()->IsOffTheRecord());
+ auto otr_browser = Browser::Create(otr_profile.get(), nullptr);
+ Tab* tab = otr_browser->CreateTab();
+
+ // There is no FaviconService for off the record profiles. FaviconService
+ // writes to disk, which is not appropriate for off the record mode.
+ EXPECT_EQ(nullptr, FaviconServiceImplFactory::GetForBrowserContext(
+ otr_profile_impl->GetBrowserContext()));
+ ASSERT_TRUE(embedded_test_server()->Start());
+ TestFaviconFetcherDelegate fetcher_delegate;
+ auto fetcher = tab->CreateFaviconFetcher(&fetcher_delegate);
+ NavigateAndWaitForCompletion(
+ embedded_test_server()->GetURL("/simple_page_with_favicon.html"), tab);
+ fetcher_delegate.WaitForFavicon();
+ EXPECT_FALSE(fetcher_delegate.last_image().IsEmpty());
+ EXPECT_EQ(fetcher_delegate.last_image(), fetcher->GetFavicon());
+ EXPECT_EQ(1, fetcher_delegate.on_favicon_changed_call_count());
+}
+#endif
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/favicon_fetcher_impl.cc b/chromium/weblayer/browser/favicon/favicon_fetcher_impl.cc
new file mode 100644
index 00000000000..d333ff22187
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_fetcher_impl.cc
@@ -0,0 +1,27 @@
+// Copyright 2020 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 "weblayer/browser/favicon/favicon_fetcher_impl.h"
+
+#include "ui/gfx/image/image.h"
+#include "weblayer/browser/favicon/favicon_tab_helper.h"
+#include "weblayer/public/favicon_fetcher_delegate.h"
+
+#include "base/logging.h"
+
+namespace weblayer {
+
+FaviconFetcherImpl::FaviconFetcherImpl(content::WebContents* web_contents,
+ FaviconFetcherDelegate* delegate)
+ : web_contents_(web_contents),
+ observer_subscription_(FaviconTabHelper::FromWebContents(web_contents)
+ ->RegisterFaviconFetcherDelegate(delegate)) {}
+
+FaviconFetcherImpl::~FaviconFetcherImpl() = default;
+
+gfx::Image FaviconFetcherImpl::GetFavicon() {
+ return FaviconTabHelper::FromWebContents(web_contents_)->favicon();
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/favicon_fetcher_impl.h b/chromium/weblayer/browser/favicon/favicon_fetcher_impl.h
new file mode 100644
index 00000000000..3a68e377b3f
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_fetcher_impl.h
@@ -0,0 +1,42 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_FAVICON_FAVICON_FETCHER_IMPL_H_
+#define WEBLAYER_BROWSER_FAVICON_FAVICON_FETCHER_IMPL_H_
+
+#include <memory>
+
+#include "weblayer/browser/favicon/favicon_tab_helper.h"
+#include "weblayer/public/favicon_fetcher.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace weblayer {
+
+class FaviconFetcherDelegate;
+
+// FaviconFetcher implementation that largely delegates to FaviconTabHelper
+// for the real implementation.
+class FaviconFetcherImpl : public FaviconFetcher {
+ public:
+ FaviconFetcherImpl(content::WebContents* web_contents,
+ FaviconFetcherDelegate* delegate);
+ FaviconFetcherImpl(const FaviconFetcherImpl&) = delete;
+ FaviconFetcherImpl& operator=(const FaviconFetcherImpl&) = delete;
+ ~FaviconFetcherImpl() override;
+
+ // FaviconFetcher:
+ gfx::Image GetFavicon() override;
+
+ private:
+ content::WebContents* web_contents_;
+ std::unique_ptr<FaviconTabHelper::ObserverSubscription>
+ observer_subscription_;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_FAVICON_FAVICON_FETCHER_IMPL_H_
diff --git a/chromium/weblayer/browser/favicon/favicon_service_impl.cc b/chromium/weblayer/browser/favicon/favicon_service_impl.cc
new file mode 100644
index 00000000000..b8ac3421677
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_service_impl.cc
@@ -0,0 +1,249 @@
+// Copyright 2020 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 "weblayer/browser/favicon/favicon_service_impl.h"
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/hash/hash.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "build/build_config.h"
+#include "components/favicon_base/favicon_util.h"
+#include "components/favicon_base/select_favicon_frames.h"
+#include "content/public/common/url_constants.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/favicon_size.h"
+#include "url/gurl.h"
+#include "weblayer/browser/favicon/favicon_backend_wrapper.h"
+#include "weblayer/browser/favicon/favicon_service_impl_observer.h"
+
+namespace weblayer {
+namespace {
+
+bool CanAddUrl(const GURL& url) {
+ if (!url.is_valid())
+ return false;
+
+ if (url.SchemeIs(url::kJavaScriptScheme) || url.SchemeIs(url::kAboutScheme) ||
+ url.SchemeIs(url::kContentScheme) ||
+ url.SchemeIs(content::kChromeDevToolsScheme) ||
+ url.SchemeIs(content::kChromeUIScheme) ||
+ url.SchemeIs(content::kViewSourceScheme)) {
+ return false;
+ }
+
+ return true;
+}
+
+// Returns the IconTypeSet for the current platform. This matches the set
+// of favicon types that are requested for the platform (see
+// FaviconDriverImpl).
+favicon_base::IconTypeSet GetIconTypeSet() {
+#if defined(OS_ANDROID)
+ return {favicon_base::IconType::kFavicon, favicon_base::IconType::kTouchIcon,
+ favicon_base::IconType::kTouchPrecomposedIcon,
+ favicon_base::IconType::kWebManifestIcon};
+#else
+ return {favicon_base::IconType::kFavicon};
+#endif
+}
+
+int GetDesiredFaviconSizeInDips() {
+#if defined(OS_ANDROID)
+ // This is treatest as the largest available icon.
+ return 0;
+#else
+ return gfx::kFaviconSize;
+#endif
+}
+
+void OnGotFaviconsForPageUrl(
+ int desired_size_in_dip,
+ base::OnceCallback<void(gfx::Image)> callback,
+ std::vector<favicon_base::FaviconRawBitmapResult> results) {
+ favicon_base::FaviconImageResult image_result;
+ image_result.image = favicon_base::SelectFaviconFramesFromPNGs(
+ results, favicon_base::GetFaviconScales(), desired_size_in_dip);
+ favicon_base::SetFaviconColorSpace(&image_result.image);
+ std::move(callback).Run(image_result.image);
+}
+
+} // namespace
+
+FaviconServiceImpl::FaviconServiceImpl() = default;
+
+FaviconServiceImpl::~FaviconServiceImpl() {
+ backend_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&FaviconBackendWrapper::Shutdown, std::move(backend_)));
+}
+
+void FaviconServiceImpl::Init(const base::FilePath& db_path) {
+ if (!backend_task_runner_) {
+ // BLOCK_SHUTDOWN matches that of HistoryService. It's done in hopes of
+ // preventing database corruption.
+ backend_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::WithBaseSyncPrimitives(),
+ base::TaskPriority::USER_BLOCKING,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
+ }
+
+ backend_ = base::MakeRefCounted<FaviconBackendWrapper>(backend_task_runner_);
+
+ backend_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&FaviconBackendWrapper::Init, backend_, db_path));
+}
+
+void FaviconServiceImpl::DeleteAndRecreateDatabase(base::OnceClosure callback) {
+ backend_task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::BindOnce(&FaviconBackendWrapper::DeleteAndRecreateDatabase,
+ backend_),
+ std::move(callback));
+}
+
+base::CancelableTaskTracker::TaskId FaviconServiceImpl::GetFaviconForPageUrl(
+ const GURL& page_url,
+ base::OnceCallback<void(gfx::Image)> callback,
+ base::CancelableTaskTracker* tracker) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // The arguments supplied to this function should return an image matching
+ // that returned by FaviconFetcher.
+ return tracker->PostTaskAndReplyWithResult(
+ backend_task_runner_.get(), FROM_HERE,
+ base::BindOnce(&FaviconBackendWrapper::GetFaviconsForUrl, backend_,
+ page_url, GetIconTypeSet(),
+ GetDesiredFaviconSizesInPixels()),
+ base::BindOnce(&OnGotFaviconsForPageUrl, GetDesiredFaviconSizeInDips(),
+ std::move(callback)));
+}
+
+base::CancelableTaskTracker::TaskId FaviconServiceImpl::GetFaviconForPageURL(
+ const GURL& page_url,
+ const favicon_base::IconTypeSet& icon_types,
+ int desired_size_in_dip,
+ favicon_base::FaviconResultsCallback callback,
+ base::CancelableTaskTracker* tracker) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return tracker->PostTaskAndReplyWithResult(
+ backend_task_runner_.get(), FROM_HERE,
+ base::BindOnce(&FaviconBackendWrapper::GetFaviconsForUrl, backend_,
+ page_url, icon_types,
+ GetPixelSizesForFaviconScales(desired_size_in_dip)),
+ std::move(callback));
+}
+
+void FaviconServiceImpl::SetFaviconOutOfDateForPage(const GURL& page_url) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ backend_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&FaviconBackendWrapper::SetFaviconsOutOfDateForPage,
+ backend_, page_url));
+}
+
+void FaviconServiceImpl::SetFavicons(const base::flat_set<GURL>& page_urls,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const gfx::Image& image) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ base::flat_set<GURL> page_urls_to_save;
+ page_urls_to_save.reserve(page_urls.capacity());
+ for (const GURL& page_url : page_urls) {
+ if (CanAddUrl(page_url))
+ page_urls_to_save.insert(page_url);
+ }
+
+ if (page_urls_to_save.empty())
+ return;
+
+ backend_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&FaviconBackendWrapper::SetFavicons, backend_,
+ page_urls_to_save, icon_type, icon_url,
+ ExtractSkBitmapsToStore(image)));
+}
+
+void FaviconServiceImpl::CloneFaviconMappingsForPages(
+ const GURL& page_url_to_read,
+ const favicon_base::IconTypeSet& icon_types,
+ const base::flat_set<GURL>& page_urls_to_write) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ backend_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&FaviconBackendWrapper::CloneFaviconMappingsForPages,
+ backend_, page_url_to_read, icon_types,
+ page_urls_to_write));
+}
+
+base::CancelableTaskTracker::TaskId FaviconServiceImpl::GetFavicon(
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ int desired_size_in_dip,
+ favicon_base::FaviconResultsCallback callback,
+ base::CancelableTaskTracker* tracker) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return tracker->PostTaskAndReplyWithResult(
+ backend_task_runner_.get(), FROM_HERE,
+ base::BindOnce(&FaviconBackendWrapper::GetFavicon, backend_, icon_url,
+ icon_type,
+ GetPixelSizesForFaviconScales(desired_size_in_dip)),
+ std::move(callback));
+}
+
+base::CancelableTaskTracker::TaskId
+FaviconServiceImpl::UpdateFaviconMappingsAndFetch(
+ const base::flat_set<GURL>& page_urls,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ int desired_size_in_dip,
+ favicon_base::FaviconResultsCallback callback,
+ base::CancelableTaskTracker* tracker) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return tracker->PostTaskAndReplyWithResult(
+ backend_task_runner_.get(), FROM_HERE,
+ base::BindOnce(&FaviconBackendWrapper::UpdateFaviconMappingsAndFetch,
+ backend_, page_urls, icon_url, icon_type,
+ GetPixelSizesForFaviconScales(desired_size_in_dip)),
+ std::move(callback));
+}
+
+void FaviconServiceImpl::DeleteFaviconMappings(
+ const base::flat_set<GURL>& page_urls,
+ favicon_base::IconType icon_type) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ backend_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&FaviconBackendWrapper::DeleteFaviconMappings,
+ backend_, page_urls, icon_type));
+}
+
+void FaviconServiceImpl::UnableToDownloadFavicon(const GURL& icon_url) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ missing_favicon_urls_.insert(base::FastHash(icon_url.spec()));
+ if (observer_)
+ observer_->OnUnableToDownloadFavicon();
+}
+
+void FaviconServiceImpl::ClearUnableToDownloadFavicons() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ missing_favicon_urls_.clear();
+}
+
+bool FaviconServiceImpl::WasUnableToDownloadFavicon(
+ const GURL& icon_url) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ MissingFaviconUrlHash url_hash = base::FastHash(icon_url.spec());
+ return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
+}
+
+// static
+std::vector<int> FaviconServiceImpl::GetDesiredFaviconSizesInPixels() {
+ return GetPixelSizesForFaviconScales(GetDesiredFaviconSizeInDips());
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/favicon_service_impl.h b/chromium/weblayer/browser/favicon/favicon_service_impl.h
new file mode 100644
index 00000000000..4d1a71db34d
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_service_impl.h
@@ -0,0 +1,105 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_FAVICON_FAVICON_SERVICE_IMPL_H_
+#define WEBLAYER_BROWSER_FAVICON_FAVICON_SERVICE_IMPL_H_
+
+#include <unordered_set>
+
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
+#include "components/favicon/core/core_favicon_service.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace weblayer {
+
+class FaviconBackendWrapper;
+class FaviconServiceImplObserver;
+
+// FaviconServiceImpl provides the front end (ui side) access to the favicon
+// database. Most functions are processed async on the backend task-runner.
+class FaviconServiceImpl : public favicon::CoreFaviconService {
+ public:
+ FaviconServiceImpl();
+ FaviconServiceImpl(const FaviconServiceImpl&) = delete;
+ FaviconServiceImpl& operator=(const FaviconServiceImpl&) = delete;
+ ~FaviconServiceImpl() override;
+
+ void Init(const base::FilePath& db_path);
+
+ void set_observer(FaviconServiceImplObserver* observer) {
+ observer_ = observer;
+ }
+
+ // Deletes the database and recreates it, notifying |callback| when done.
+ void DeleteAndRecreateDatabase(base::OnceClosure callback);
+
+ // Requests the favicon image for a url (page). The returned image matches
+ // that returned from FaviconFetcher.
+ base::CancelableTaskTracker::TaskId GetFaviconForPageUrl(
+ const GURL& page_url,
+ base::OnceCallback<void(gfx::Image)> callback,
+ base::CancelableTaskTracker* tracker);
+
+ // favicon::CoreFaviconService:
+ base::CancelableTaskTracker::TaskId GetFaviconForPageURL(
+ const GURL& page_url,
+ const favicon_base::IconTypeSet& icon_types,
+ int desired_size_in_dip,
+ favicon_base::FaviconResultsCallback callback,
+ base::CancelableTaskTracker* tracker) override;
+ void SetFaviconOutOfDateForPage(const GURL& page_url) override;
+ void SetFavicons(const base::flat_set<GURL>& page_urls,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const gfx::Image& image) override;
+ void CloneFaviconMappingsForPages(
+ const GURL& page_url_to_read,
+ const favicon_base::IconTypeSet& icon_types,
+ const base::flat_set<GURL>& page_urls_to_write) override;
+ base::CancelableTaskTracker::TaskId GetFavicon(
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ int desired_size_in_dip,
+ favicon_base::FaviconResultsCallback callback,
+ base::CancelableTaskTracker* tracker) override;
+ base::CancelableTaskTracker::TaskId UpdateFaviconMappingsAndFetch(
+ const base::flat_set<GURL>& page_urls,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ int desired_size_in_dip,
+ favicon_base::FaviconResultsCallback callback,
+ base::CancelableTaskTracker* tracker) override;
+ void DeleteFaviconMappings(const base::flat_set<GURL>& page_urls,
+ favicon_base::IconType icon_type) override;
+ void UnableToDownloadFavicon(const GURL& icon_url) override;
+ void ClearUnableToDownloadFavicons() override;
+ bool WasUnableToDownloadFavicon(const GURL& icon_url) const override;
+
+ private:
+ using MissingFaviconUrlHash = size_t;
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // Returns the desired favicon sizes for the current platform.
+ static std::vector<int> GetDesiredFaviconSizesInPixels();
+
+ // The TaskRunner to which FaviconServiceBackend tasks are posted. Nullptr
+ // once Cleanup() is called.
+ scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
+
+ scoped_refptr<FaviconBackendWrapper> backend_;
+
+ // Hashes of the favicon urls that were unable to be downloaded.
+ std::unordered_set<MissingFaviconUrlHash> missing_favicon_urls_;
+
+ // This is only used in tests, where only a single observer is necessary.
+ FaviconServiceImplObserver* observer_ = nullptr;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_FAVICON_FAVICON_SERVICE_IMPL_H_
diff --git a/chromium/weblayer/browser/favicon/favicon_service_impl_factory.cc b/chromium/weblayer/browser/favicon/favicon_service_impl_factory.cc
new file mode 100644
index 00000000000..f75045536f2
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_service_impl_factory.cc
@@ -0,0 +1,50 @@
+// Copyright 2020 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 "weblayer/browser/favicon/favicon_service_impl_factory.h"
+
+#include "base/files/file_path.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+#include "weblayer/browser/favicon/favicon_service_impl.h"
+
+namespace weblayer {
+
+// static
+FaviconServiceImpl* FaviconServiceImplFactory::GetForBrowserContext(
+ content::BrowserContext* browser_context) {
+ if (!browser_context->IsOffTheRecord()) {
+ return static_cast<FaviconServiceImpl*>(
+ GetInstance()->GetServiceForBrowserContext(browser_context, true));
+ }
+ return nullptr;
+}
+
+// static
+FaviconServiceImplFactory* FaviconServiceImplFactory::GetInstance() {
+ static base::NoDestructor<FaviconServiceImplFactory> factory;
+ return factory.get();
+}
+
+FaviconServiceImplFactory::FaviconServiceImplFactory()
+ : BrowserContextKeyedServiceFactory(
+ "FaviconServiceImpl",
+ BrowserContextDependencyManager::GetInstance()) {}
+
+FaviconServiceImplFactory::~FaviconServiceImplFactory() = default;
+
+KeyedService* FaviconServiceImplFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ DCHECK(!context->IsOffTheRecord());
+ std::unique_ptr<FaviconServiceImpl> service =
+ std::make_unique<FaviconServiceImpl>();
+ service->Init(context->GetPath().AppendASCII("Favicons"));
+ return service.release();
+}
+
+bool FaviconServiceImplFactory::ServiceIsNULLWhileTesting() const {
+ return true;
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/favicon_service_impl_factory.h b/chromium/weblayer/browser/favicon/favicon_service_impl_factory.h
new file mode 100644
index 00000000000..f852eb6389d
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_service_impl_factory.h
@@ -0,0 +1,47 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_FAVICON_FAVICON_SERVICE_IMPL_FACTORY_H_
+#define WEBLAYER_BROWSER_FAVICON_FAVICON_SERVICE_IMPL_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace weblayer {
+
+class FaviconServiceImpl;
+
+// BrowserContextKeyedServiceFactory for getting the FaviconServiceImpl.
+class FaviconServiceImplFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ FaviconServiceImplFactory(const FaviconServiceImplFactory&) = delete;
+ FaviconServiceImplFactory& operator=(const FaviconServiceImplFactory&) =
+ delete;
+
+ // Off the record profiles do not have a FaviconServiceImpl.
+ static FaviconServiceImpl* GetForBrowserContext(
+ content::BrowserContext* browser_context);
+
+ // Returns the FaviconServiceFactory singleton.
+ static FaviconServiceImplFactory* GetInstance();
+
+ private:
+ friend class base::NoDestructor<FaviconServiceImplFactory>;
+
+ FaviconServiceImplFactory();
+ ~FaviconServiceImplFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const override;
+ bool ServiceIsNULLWhileTesting() const override;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_FAVICON_FAVICON_SERVICE_IMPL_FACTORY_H_
diff --git a/chromium/weblayer/browser/favicon/favicon_service_impl_observer.h b/chromium/weblayer/browser/favicon/favicon_service_impl_observer.h
new file mode 100644
index 00000000000..ea647045074
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_service_impl_observer.h
@@ -0,0 +1,21 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_FAVICON_FAVICON_SERVICE_IMPL_OBSERVER_H_
+#define WEBLAYER_BROWSER_FAVICON_FAVICON_SERVICE_IMPL_OBSERVER_H_
+
+namespace weblayer {
+
+class FaviconServiceImplObserver {
+ public:
+ // Called from FaviconServiceImpl::UnableToDownloadFavicon.
+ virtual void OnUnableToDownloadFavicon() {}
+
+ protected:
+ virtual ~FaviconServiceImplObserver() = default;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_FAVICON_FAVICON_SERVICE_IMPL_OBSERVER_H_
diff --git a/chromium/weblayer/browser/favicon/favicon_tab_helper.cc b/chromium/weblayer/browser/favicon/favicon_tab_helper.cc
new file mode 100644
index 00000000000..4abff65e7d3
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_tab_helper.cc
@@ -0,0 +1,124 @@
+// Copyright 2020 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 "weblayer/browser/favicon/favicon_tab_helper.h"
+
+#include "components/favicon/content/content_favicon_driver.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "weblayer/browser/favicon/favicon_service_impl.h"
+#include "weblayer/browser/favicon/favicon_service_impl_factory.h"
+#include "weblayer/public/favicon_fetcher_delegate.h"
+
+namespace weblayer {
+namespace {
+
+bool IsSquareImage(const gfx::Image& image) {
+ return !image.IsEmpty() && image.Width() == image.Height();
+}
+
+// Returns true if |image_a| is better than |image_b|. A value of false means
+// |image_a| is not better than |image_b|. Either image may be empty, if both
+// are empty false is returned.
+bool IsImageBetterThan(const gfx::Image& image_a, const gfx::Image& image_b) {
+ // Any image is better than an empty image.
+ if (!image_a.IsEmpty() && image_b.IsEmpty())
+ return true;
+
+ // Prefer square favicons as they will scale much better.
+ if (IsSquareImage(image_a) && !IsSquareImage(image_b))
+ return true;
+
+ return image_a.Width() > image_b.Width();
+}
+
+} // namespace
+
+FaviconTabHelper::ObserverSubscription::ObserverSubscription(
+ FaviconTabHelper* helper,
+ FaviconFetcherDelegate* delegate)
+ : helper_(helper), delegate_(delegate) {
+ helper_->AddDelegate(delegate_);
+}
+
+FaviconTabHelper::ObserverSubscription::~ObserverSubscription() {
+ helper_->RemoveDelegate(delegate_);
+}
+
+FaviconTabHelper::~FaviconTabHelper() {
+ // All of the ObserverSubscriptions should have been destroyed before this.
+ DCHECK_EQ(0, observer_count_);
+}
+
+std::unique_ptr<FaviconTabHelper::ObserverSubscription>
+FaviconTabHelper::RegisterFaviconFetcherDelegate(
+ FaviconFetcherDelegate* delegate) {
+ // WrapUnique as constructor is private.
+ return base::WrapUnique(new ObserverSubscription(this, delegate));
+}
+
+FaviconTabHelper::FaviconTabHelper(content::WebContents* contents)
+ : WebContentsObserver(contents) {
+}
+
+void FaviconTabHelper::AddDelegate(FaviconFetcherDelegate* delegate) {
+ delegates_.AddObserver(delegate);
+ if (++observer_count_ == 1) {
+ FaviconServiceImpl* favicon_service =
+ FaviconServiceImplFactory::GetForBrowserContext(
+ web_contents()->GetBrowserContext());
+ favicon::ContentFaviconDriver::CreateForWebContents(web_contents(),
+ favicon_service);
+ favicon::ContentFaviconDriver::FromWebContents(web_contents())
+ ->AddObserver(this);
+ }
+}
+
+void FaviconTabHelper::RemoveDelegate(FaviconFetcherDelegate* delegate) {
+ delegates_.RemoveObserver(delegate);
+ --observer_count_;
+ DCHECK_GE(observer_count_, 0);
+ if (observer_count_ == 0) {
+ favicon::ContentFaviconDriver::FromWebContents(web_contents())
+ ->RemoveObserver(this);
+ // ContentFaviconDriver downloads images, if there are no observers there
+ // is no need to keep it around. This triggers deleting it.
+ web_contents()->SetUserData(favicon::ContentFaviconDriver::UserDataKey(),
+ nullptr);
+ favicon_ = gfx::Image();
+ }
+}
+
+void FaviconTabHelper::OnFaviconUpdated(
+ favicon::FaviconDriver* favicon_driver,
+ NotificationIconType notification_icon_type,
+ const GURL& icon_url,
+ bool icon_url_changed,
+ const gfx::Image& image) {
+ if (!IsImageBetterThan(image, favicon_))
+ return;
+
+ favicon_ = image;
+ for (FaviconFetcherDelegate& delegate : delegates_)
+ delegate.OnFaviconChanged(favicon_);
+}
+
+void FaviconTabHelper::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (!navigation_handle->IsInMainFrame() ||
+ !navigation_handle->HasCommitted() || navigation_handle->IsErrorPage() ||
+ navigation_handle->IsSameDocument()) {
+ return;
+ }
+ if (favicon_.IsEmpty())
+ return;
+
+ favicon_ = gfx::Image();
+ for (FaviconFetcherDelegate& delegate : delegates_)
+ delegate.OnFaviconChanged(favicon_);
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(FaviconTabHelper)
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/favicon_tab_helper.h b/chromium/weblayer/browser/favicon/favicon_tab_helper.h
new file mode 100644
index 00000000000..5558ab16665
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/favicon_tab_helper.h
@@ -0,0 +1,87 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_FAVICON_FAVICON_TAB_HELPER_H_
+#define WEBLAYER_BROWSER_FAVICON_FAVICON_TAB_HELPER_H_
+
+#include <memory>
+
+#include "base/observer_list.h"
+#include "components/favicon/core/favicon_driver_observer.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "ui/gfx/image/image.h"
+
+namespace weblayer {
+
+class FaviconFetcherDelegate;
+
+// FaviconTabHelper is responsible for creating favicon::ContentFaviconDriver
+// when necessary. FaviconTabHelper is used by FaviconFetcherImpl and notifies
+// FaviconFetcherDelegate when the favicon changes.
+class FaviconTabHelper : public content::WebContentsUserData<FaviconTabHelper>,
+ public content::WebContentsObserver,
+ public favicon::FaviconDriverObserver {
+ public:
+ // Used to track calls to RegisterFaviconFetcherDelegate(). When destroyed
+ // the FaviconFetcherDelegate is removed.
+ class ObserverSubscription {
+ public:
+ ObserverSubscription(const ObserverSubscription&) = delete;
+ ObserverSubscription& operator=(const ObserverSubscription&) = delete;
+ ~ObserverSubscription();
+
+ private:
+ friend class FaviconTabHelper;
+
+ ObserverSubscription(FaviconTabHelper* helper,
+ FaviconFetcherDelegate* delegate);
+
+ FaviconTabHelper* helper_;
+ FaviconFetcherDelegate* delegate_;
+ };
+
+ FaviconTabHelper(const FaviconTabHelper&) = delete;
+ FaviconTabHelper& operator=(const FaviconTabHelper&) = delete;
+ ~FaviconTabHelper() override;
+
+ // Called when FaviconFetcherImpl is created. This ensures the necessary
+ // wiring is in place and notifies |delegate| when the favicon changes.
+ std::unique_ptr<ObserverSubscription> RegisterFaviconFetcherDelegate(
+ FaviconFetcherDelegate* delegate);
+
+ // Returns the favicon for the current navigation.
+ const gfx::Image& favicon() const { return favicon_; }
+
+ private:
+ friend class content::WebContentsUserData<FaviconTabHelper>;
+
+ explicit FaviconTabHelper(content::WebContents* contents);
+
+ void AddDelegate(FaviconFetcherDelegate* delegate);
+ void RemoveDelegate(FaviconFetcherDelegate* delegate);
+
+ // favicon::FaviconDriverObserver:
+ void OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
+ NotificationIconType notification_icon_type,
+ const GURL& icon_url,
+ bool icon_url_changed,
+ const gfx::Image& image) override;
+
+ // content::WebContentsObserver:
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+
+ content::WebContents* web_contents_;
+ // Number of observers attached.
+ int observer_count_ = 0;
+ base::ObserverList<FaviconFetcherDelegate> delegates_;
+ gfx::Image favicon_;
+
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_FAVICON_FAVICON_TAB_HELPER_H_
diff --git a/chromium/weblayer/browser/favicon/test_favicon_fetcher_delegate.cc b/chromium/weblayer/browser/favicon/test_favicon_fetcher_delegate.cc
new file mode 100644
index 00000000000..7c79fe1214a
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/test_favicon_fetcher_delegate.cc
@@ -0,0 +1,46 @@
+// Copyright 2020 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 "weblayer/browser/favicon/test_favicon_fetcher_delegate.h"
+
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace weblayer {
+
+TestFaviconFetcherDelegate::TestFaviconFetcherDelegate() = default;
+
+TestFaviconFetcherDelegate::~TestFaviconFetcherDelegate() = default;
+
+void TestFaviconFetcherDelegate::WaitForFavicon() {
+ ASSERT_EQ(nullptr, run_loop_.get());
+ waiting_for_nonempty_image_ = false;
+ run_loop_ = std::make_unique<base::RunLoop>();
+ run_loop_->Run();
+ run_loop_.reset();
+}
+
+void TestFaviconFetcherDelegate::WaitForNonemptyFavicon() {
+ if (!last_image_.IsEmpty())
+ return;
+
+ run_loop_ = std::make_unique<base::RunLoop>();
+ waiting_for_nonempty_image_ = true;
+ run_loop_->Run();
+ run_loop_.reset();
+}
+
+void TestFaviconFetcherDelegate::ClearLastImage() {
+ last_image_ = gfx::Image();
+ on_favicon_changed_call_count_ = 0;
+}
+
+void TestFaviconFetcherDelegate::OnFaviconChanged(const gfx::Image& image) {
+ last_image_ = image;
+ ++on_favicon_changed_call_count_;
+ if (run_loop_ && (!waiting_for_nonempty_image_ || !image.IsEmpty()))
+ run_loop_->Quit();
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/favicon/test_favicon_fetcher_delegate.h b/chromium/weblayer/browser/favicon/test_favicon_fetcher_delegate.h
new file mode 100644
index 00000000000..25300a85ebc
--- /dev/null
+++ b/chromium/weblayer/browser/favicon/test_favicon_fetcher_delegate.h
@@ -0,0 +1,55 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_FAVICON_TEST_FAVICON_FETCHER_DELEGATE_H_
+#define WEBLAYER_BROWSER_FAVICON_TEST_FAVICON_FETCHER_DELEGATE_H_
+
+#include <memory>
+
+#include "ui/gfx/image/image.h"
+#include "weblayer/public/favicon_fetcher_delegate.h"
+
+namespace base {
+class RunLoop;
+}
+
+namespace weblayer {
+
+// Records calls to OnFaviconChanged().
+class TestFaviconFetcherDelegate : public FaviconFetcherDelegate {
+ public:
+ TestFaviconFetcherDelegate();
+ TestFaviconFetcherDelegate(const TestFaviconFetcherDelegate&) = delete;
+ TestFaviconFetcherDelegate& operator=(const TestFaviconFetcherDelegate&) =
+ delete;
+ ~TestFaviconFetcherDelegate() override;
+
+ // Waits for OnFaviconChanged() to be called.
+ void WaitForFavicon();
+
+ // Waits for a non-empty favicon. This returns immediately if a non-empty
+ // image was supplied to OnFaviconChanged() and ClearLastImage() hasn't been
+ // called.
+ void WaitForNonemptyFavicon();
+
+ void ClearLastImage();
+
+ const gfx::Image& last_image() const { return last_image_; }
+ int on_favicon_changed_call_count() const {
+ return on_favicon_changed_call_count_;
+ }
+
+ // FaviconFetcherDelegate:
+ void OnFaviconChanged(const gfx::Image& image) override;
+
+ private:
+ std::unique_ptr<base::RunLoop> run_loop_;
+ gfx::Image last_image_;
+ bool waiting_for_nonempty_image_ = false;
+ int on_favicon_changed_call_count_ = 0;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_FAVICON_TEST_FAVICON_FETCHER_DELEGATE_H_
diff --git a/chromium/weblayer/browser/file_select_helper.cc b/chromium/weblayer/browser/file_select_helper.cc
index 7cc0a81e87d..2e462571ab1 100644
--- a/chromium/weblayer/browser/file_select_helper.cc
+++ b/chromium/weblayer/browser/file_select_helper.cc
@@ -27,7 +27,7 @@ using blink::mojom::FileChooserParamsPtr;
// static
void FileSelectHelper::RunFileChooser(
content::RenderFrameHost* render_frame_host,
- std::unique_ptr<content::FileSelectListener> listener,
+ scoped_refptr<content::FileSelectListener> listener,
const FileChooserParams& params) {
// TODO: Should we handle text/json+contacts accept type?
@@ -49,7 +49,7 @@ FileSelectHelper::~FileSelectHelper() {
void FileSelectHelper::RunFileChooser(
content::RenderFrameHost* render_frame_host,
- std::unique_ptr<content::FileSelectListener> listener,
+ scoped_refptr<content::FileSelectListener> listener,
FileChooserParamsPtr params) {
DCHECK(!web_contents());
DCHECK(listener);
diff --git a/chromium/weblayer/browser/file_select_helper.h b/chromium/weblayer/browser/file_select_helper.h
index a99977429f6..5619e72a68a 100644
--- a/chromium/weblayer/browser/file_select_helper.h
+++ b/chromium/weblayer/browser/file_select_helper.h
@@ -40,7 +40,7 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
// Show the file chooser dialog.
static void RunFileChooser(
content::RenderFrameHost* render_frame_host,
- std::unique_ptr<content::FileSelectListener> listener,
+ scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params);
private:
@@ -53,7 +53,7 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
~FileSelectHelper() override;
void RunFileChooser(content::RenderFrameHost* render_frame_host,
- std::unique_ptr<content::FileSelectListener> listener,
+ scoped_refptr<content::FileSelectListener> listener,
blink::mojom::FileChooserParamsPtr params);
// Cleans up and releases this instance. This must be called after the last
@@ -85,7 +85,7 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
bool AbortIfWebContentsDestroyed();
// |listener_| receives the result of the FileSelectHelper.
- std::unique_ptr<content::FileSelectListener> listener_;
+ scoped_refptr<content::FileSelectListener> listener_;
// Dialog box used for choosing files to upload from file form fields.
scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
diff --git a/chromium/weblayer/browser/google_accounts_browsertest.cc b/chromium/weblayer/browser/google_accounts_browsertest.cc
new file mode 100644
index 00000000000..43d25ab4032
--- /dev/null
+++ b/chromium/weblayer/browser/google_accounts_browsertest.cc
@@ -0,0 +1,229 @@
+// Copyright 2020 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 "base/strings/strcat.h"
+#include "components/signin/core/browser/signin_header_helper.h"
+#include "google_apis/gaia/gaia_switches.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "net/base/escape.h"
+#include "net/base/url_util.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/default_handlers.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "weblayer/browser/browser_impl.h"
+#include "weblayer/browser/profile_impl.h"
+#include "weblayer/browser/signin_url_loader_throttle.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/public/google_accounts_delegate.h"
+#include "weblayer/public/navigation_controller.h"
+#include "weblayer/shell/browser/shell.h"
+#include "weblayer/test/test_navigation_observer.h"
+#include "weblayer/test/weblayer_browser_test.h"
+#include "weblayer/test/weblayer_browser_test_utils.h"
+
+namespace weblayer {
+namespace {
+constexpr char kGaiaDomain[] = "fakegaia.com";
+constexpr char kGoogleAccountsPath[] = "/manageaccounts";
+constexpr char kGoogleAccountsRedirectPath[] = "/manageaccounts-redirect";
+} // namespace
+
+class GoogleAccountsBrowserTest : public WebLayerBrowserTest,
+ public GoogleAccountsDelegate {
+ public:
+ // WebLayerBrowserTest:
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ shell()->tab()->SetGoogleAccountsDelegate(this);
+ }
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ https_server_.RegisterRequestHandler(base::BindRepeating(
+ &GoogleAccountsBrowserTest::HandleGoogleAccountsRequest,
+ base::Unretained(this)));
+ net::test_server::RegisterDefaultHandlers(&https_server_);
+ ASSERT_TRUE(https_server_.Start());
+ command_line->AppendSwitchASCII(switches::kGaiaUrl, GetGaiaURL("/").spec());
+ command_line->AppendSwitch("ignore-certificate-errors");
+ }
+
+ // GoogleAccountsDelegate:
+ void OnGoogleAccountsRequest(
+ const signin::ManageAccountsParams& params) override {
+ params_ = params;
+ if (run_loop_)
+ run_loop_->Quit();
+ }
+
+ std::string GetGaiaId() override { return ""; }
+
+ const signin::ManageAccountsParams& WaitForGoogleAccounts() {
+ if (!params_) {
+ run_loop_ = std::make_unique<base::RunLoop>();
+ run_loop_->Run();
+ }
+ EXPECT_TRUE(params_.has_value());
+ return params_.value();
+ }
+
+ GURL GetGaiaURL(const std::string& path) {
+ return https_server_.GetURL(kGaiaDomain, path);
+ }
+
+ GURL GetNonGaiaURL(const std::string& path) {
+ return https_server_.GetURL(path);
+ }
+
+ bool HasReceivedGoogleAccountsResponse() { return params_.has_value(); }
+
+ std::string GetBody() {
+ return ExecuteScript(shell(), "document.body.innerText", true).GetString();
+ }
+
+ protected:
+ std::string response_header_;
+
+ private:
+ std::unique_ptr<net::test_server::HttpResponse> HandleGoogleAccountsRequest(
+ const net::test_server::HttpRequest& request) {
+ std::string path = request.GetURL().path();
+ if (path != kSignOutPath && path != kGoogleAccountsPath &&
+ path != kGoogleAccountsRedirectPath) {
+ return nullptr;
+ }
+
+ auto http_response =
+ std::make_unique<net::test_server::BasicHttpResponse>();
+ if (path == kGoogleAccountsRedirectPath) {
+ http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
+ http_response->AddCustomHeader(
+ "Location",
+ net::UnescapeBinaryURLComponent(request.GetURL().query_piece()));
+ } else {
+ http_response->set_code(net::HTTP_OK);
+ }
+
+ if (base::Contains(request.headers, signin::kChromeConnectedHeader)) {
+ http_response->AddCustomHeader(signin::kChromeManageAccountsHeader,
+ response_header_);
+ }
+ http_response->set_content("");
+ return http_response;
+ }
+
+ net::EmbeddedTestServer https_server_{net::EmbeddedTestServer::TYPE_HTTPS};
+ base::Optional<signin::ManageAccountsParams> params_;
+ std::unique_ptr<base::RunLoop> run_loop_;
+};
+
+IN_PROC_BROWSER_TEST_F(GoogleAccountsBrowserTest, Basic) {
+ response_header_ =
+ "action=ADDSESSION,email=foo@bar.com,"
+ "continue_url=https://blah.com,is_same_tab=true";
+ NavigateAndWaitForCompletion(GetGaiaURL(kGoogleAccountsPath), shell());
+ const signin::ManageAccountsParams& params = WaitForGoogleAccounts();
+ EXPECT_EQ(params.service_type, signin::GAIA_SERVICE_TYPE_ADDSESSION);
+ EXPECT_EQ(params.email, "foo@bar.com");
+ EXPECT_EQ(params.continue_url, "https://blah.com");
+ EXPECT_TRUE(params.is_same_tab);
+}
+
+IN_PROC_BROWSER_TEST_F(GoogleAccountsBrowserTest, NonGaiaUrl) {
+ response_header_ = "action=ADDSESSION";
+ NavigateAndWaitForCompletion(GetNonGaiaURL(kGoogleAccountsPath), shell());
+
+ // Navigate again to make sure the manage accounts response would have been
+ // received.
+ NavigateAndWaitForCompletion(GetNonGaiaURL("/echo"), shell());
+ EXPECT_FALSE(HasReceivedGoogleAccountsResponse());
+}
+
+IN_PROC_BROWSER_TEST_F(GoogleAccountsBrowserTest, RedirectFromGaiaURL) {
+ response_header_ = "action=SIGNUP";
+
+ GURL final_url = GetGaiaURL(kGoogleAccountsPath);
+ TestNavigationObserver test_observer(
+ final_url, TestNavigationObserver::NavigationEvent::kCompletion,
+ shell()->tab());
+ shell()->tab()->GetNavigationController()->Navigate(GetNonGaiaURL(
+ base::StrCat({kGoogleAccountsRedirectPath, "?", final_url.spec()})));
+ test_observer.Wait();
+
+ const signin::ManageAccountsParams& params = WaitForGoogleAccounts();
+ EXPECT_EQ(params.service_type, signin::GAIA_SERVICE_TYPE_SIGNUP);
+}
+
+IN_PROC_BROWSER_TEST_F(GoogleAccountsBrowserTest, RedirectToGaiaURL) {
+ response_header_ = "action=SIGNUP";
+
+ GURL final_url = GetNonGaiaURL(kGoogleAccountsPath);
+ TestNavigationObserver test_observer(
+ final_url, TestNavigationObserver::NavigationEvent::kCompletion,
+ shell()->tab());
+ shell()->tab()->GetNavigationController()->Navigate(GetGaiaURL(
+ base::StrCat({kGoogleAccountsRedirectPath, "?", final_url.spec()})));
+ test_observer.Wait();
+
+ const signin::ManageAccountsParams& params = WaitForGoogleAccounts();
+ EXPECT_EQ(params.service_type, signin::GAIA_SERVICE_TYPE_SIGNUP);
+}
+
+IN_PROC_BROWSER_TEST_F(GoogleAccountsBrowserTest, AddsQueryParamsToSignoutURL) {
+ response_header_ = "action=SIGNUP";
+
+ // Sign out URL on the GAIA domain will get a query param added to it.
+ GURL sign_out_url = GetGaiaURL(kSignOutPath);
+ GURL sign_out_url_with_params =
+ net::AppendQueryParameter(sign_out_url, "manage", "true");
+ {
+ TestNavigationObserver test_observer(
+ sign_out_url_with_params,
+ TestNavigationObserver::NavigationEvent::kCompletion, shell()->tab());
+ shell()->tab()->GetNavigationController()->Navigate(sign_out_url);
+ test_observer.Wait();
+ }
+
+ // Other URLs will not have query param added.
+ NavigateAndWaitForCompletion(GetGaiaURL(kGoogleAccountsPath), shell());
+ NavigateAndWaitForCompletion(GetNonGaiaURL(kSignOutPath), shell());
+
+ // Redirecting to sign out URL will also add params.
+ {
+ TestNavigationObserver test_observer(
+ sign_out_url_with_params,
+ TestNavigationObserver::NavigationEvent::kCompletion, shell()->tab());
+ shell()->tab()->GetNavigationController()->Navigate(
+ GetNonGaiaURL("/server-redirect?" + sign_out_url.spec()));
+ test_observer.Wait();
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(GoogleAccountsBrowserTest, AddsRequestHeaderToGaiaURLs) {
+ const std::string path =
+ base::StrCat({"/echoheader?", signin::kChromeConnectedHeader});
+ NavigateAndWaitForCompletion(GetGaiaURL(path), shell());
+ EXPECT_EQ(GetBody(),
+ "source=WebLayer,mode=3,enable_account_consistency=true,"
+ "consistency_enabled_by_default=false");
+
+ // Non GAIA URL should not get the header.
+ NavigateAndWaitForCompletion(GetNonGaiaURL(path), shell());
+ EXPECT_EQ(GetBody(), "None");
+}
+
+class IncognitoGoogleAccountsBrowserTest : public GoogleAccountsBrowserTest {
+ public:
+ IncognitoGoogleAccountsBrowserTest() { SetShellStartsInIncognitoMode(); }
+};
+
+IN_PROC_BROWSER_TEST_F(IncognitoGoogleAccountsBrowserTest,
+ HeaderNotAddedForIncognitoBrowser) {
+ const std::string path =
+ base::StrCat({"/echoheader?", signin::kChromeConnectedHeader});
+ NavigateAndWaitForCompletion(GetGaiaURL(path), shell());
+ EXPECT_EQ(GetBody(), "None");
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/google_accounts_callback_proxy.cc b/chromium/weblayer/browser/google_accounts_callback_proxy.cc
new file mode 100644
index 00000000000..1464b904327
--- /dev/null
+++ b/chromium/weblayer/browser/google_accounts_callback_proxy.cc
@@ -0,0 +1,57 @@
+// Copyright 2020 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 "weblayer/browser/google_accounts_callback_proxy.h"
+
+#include "base/android/jni_string.h"
+#include "components/signin/core/browser/signin_header_helper.h"
+#include "weblayer/browser/java/jni/GoogleAccountsCallbackProxy_jni.h"
+#include "weblayer/public/tab.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF8ToJavaString;
+
+namespace weblayer {
+
+GoogleAccountsCallbackProxy::GoogleAccountsCallbackProxy(JNIEnv* env,
+ jobject obj,
+ Tab* tab)
+ : tab_(tab), java_impl_(env, obj) {
+ tab_->SetGoogleAccountsDelegate(this);
+}
+
+GoogleAccountsCallbackProxy::~GoogleAccountsCallbackProxy() {
+ tab_->SetGoogleAccountsDelegate(nullptr);
+}
+
+void GoogleAccountsCallbackProxy::OnGoogleAccountsRequest(
+ const signin::ManageAccountsParams& params) {
+ JNIEnv* env = AttachCurrentThread();
+ Java_GoogleAccountsCallbackProxy_onGoogleAccountsRequest(
+ env, java_impl_, params.service_type,
+ ConvertUTF8ToJavaString(env, params.email),
+ ConvertUTF8ToJavaString(env, params.continue_url), params.is_same_tab);
+}
+
+std::string GoogleAccountsCallbackProxy::GetGaiaId() {
+ return base::android::ConvertJavaStringToUTF8(
+ Java_GoogleAccountsCallbackProxy_getGaiaId(AttachCurrentThread(),
+ java_impl_));
+}
+
+static jlong JNI_GoogleAccountsCallbackProxy_CreateGoogleAccountsCallbackProxy(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& proxy,
+ jlong tab) {
+ return reinterpret_cast<jlong>(
+ new GoogleAccountsCallbackProxy(env, proxy, reinterpret_cast<Tab*>(tab)));
+}
+
+static void JNI_GoogleAccountsCallbackProxy_DeleteGoogleAccountsCallbackProxy(
+ JNIEnv* env,
+ jlong proxy) {
+ delete reinterpret_cast<GoogleAccountsCallbackProxy*>(proxy);
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/google_accounts_callback_proxy.h b/chromium/weblayer/browser/google_accounts_callback_proxy.h
new file mode 100644
index 00000000000..577fb305a4c
--- /dev/null
+++ b/chromium/weblayer/browser/google_accounts_callback_proxy.h
@@ -0,0 +1,34 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_GOOGLE_ACCOUNTS_CALLBACK_PROXY_H_
+#define WEBLAYER_BROWSER_GOOGLE_ACCOUNTS_CALLBACK_PROXY_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "weblayer/public/google_accounts_delegate.h"
+
+namespace weblayer {
+
+class Tab;
+
+class GoogleAccountsCallbackProxy : public GoogleAccountsDelegate {
+ public:
+ GoogleAccountsCallbackProxy(JNIEnv* env, jobject obj, Tab* tab);
+ ~GoogleAccountsCallbackProxy() override;
+
+ // GoogleAccountsDelegate:
+ void OnGoogleAccountsRequest(
+ const signin::ManageAccountsParams& params) override;
+ std::string GetGaiaId() override;
+
+ private:
+ Tab* tab_;
+ base::android::ScopedJavaGlobalRef<jobject> java_impl_;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_GOOGLE_ACCOUNTS_CALLBACK_PROXY_H_
diff --git a/chromium/weblayer/browser/infobar_android.cc b/chromium/weblayer/browser/infobar_android.cc
deleted file mode 100644
index 4aa24af9285..00000000000
--- a/chromium/weblayer/browser/infobar_android.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2020 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 "weblayer/browser/infobar_android.h"
-
-#include <utility>
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/strings/string_util.h"
-#include "components/infobars/core/infobar.h"
-#include "components/infobars/core/infobar_delegate.h"
-#include "weblayer/browser/android/resource_mapper.h"
-#include "weblayer/browser/java/jni/InfoBar_jni.h"
-
-using base::android::JavaParamRef;
-using base::android::JavaRef;
-
-namespace weblayer {
-
-// InfoBarAndroid -------------------------------------------------------------
-
-InfoBarAndroid::InfoBarAndroid(
- std::unique_ptr<infobars::InfoBarDelegate> delegate)
- : infobars::InfoBar(std::move(delegate)) {}
-
-InfoBarAndroid::~InfoBarAndroid() {
- if (!java_info_bar_.is_null()) {
- JNIEnv* env = base::android::AttachCurrentThread();
- Java_InfoBar_onNativeDestroyed(env, java_info_bar_);
- }
-}
-
-void InfoBarAndroid::ReassignJavaInfoBar(InfoBarAndroid* replacement) {
- DCHECK(replacement);
- if (!java_info_bar_.is_null()) {
- replacement->SetJavaInfoBar(java_info_bar_);
- java_info_bar_.Reset();
- }
-}
-
-void InfoBarAndroid::SetJavaInfoBar(
- const base::android::JavaRef<jobject>& java_info_bar) {
- DCHECK(java_info_bar_.is_null());
- java_info_bar_.Reset(java_info_bar);
- JNIEnv* env = base::android::AttachCurrentThread();
- Java_InfoBar_setNativeInfoBar(env, java_info_bar,
- reinterpret_cast<intptr_t>(this));
-}
-
-const JavaRef<jobject>& InfoBarAndroid::GetJavaInfoBar() {
- return java_info_bar_;
-}
-
-bool InfoBarAndroid::HasSetJavaInfoBar() const {
- return !java_info_bar_.is_null();
-}
-
-int InfoBarAndroid::GetInfoBarIdentifier(JNIEnv* env,
- const JavaParamRef<jobject>& obj) {
- return delegate()->GetIdentifier();
-}
-
-void InfoBarAndroid::OnButtonClicked(JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- jint action) {
- ProcessButton(action);
-}
-
-void InfoBarAndroid::OnCloseButtonClicked(JNIEnv* env,
- const JavaParamRef<jobject>& obj) {
- if (!owner())
- return; // We're closing; don't call anything, it might access the owner.
- delegate()->InfoBarDismissed();
- RemoveSelf();
-}
-
-void InfoBarAndroid::CloseJavaInfoBar() {
- if (!java_info_bar_.is_null()) {
- JNIEnv* env = base::android::AttachCurrentThread();
- Java_InfoBar_closeInfoBar(env, java_info_bar_);
- java_info_bar_.Reset(nullptr);
- }
-}
-
-int InfoBarAndroid::GetJavaIconId() {
- return weblayer::MapToJavaDrawableId(delegate()->GetIconId());
-}
-
-} // namespace weblayer
diff --git a/chromium/weblayer/browser/infobar_android.h b/chromium/weblayer/browser/infobar_android.h
deleted file mode 100644
index 5c319688cff..00000000000
--- a/chromium/weblayer/browser/infobar_android.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2020 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 WEBLAYER_BROWSER_INFOBAR_ANDROID_H_
-#define WEBLAYER_BROWSER_INFOBAR_ANDROID_H_
-
-#include <string>
-
-#include "base/android/scoped_java_ref.h"
-#include "base/macros.h"
-#include "components/infobars/core/infobar.h"
-
-namespace infobars {
-class InfoBarDelegate;
-}
-
-namespace weblayer {
-
-class InfoBarAndroid : public infobars::InfoBar {
- public:
- // A Java counterpart will be generated for this enum.
- // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.weblayer_private
- // GENERATED_JAVA_PREFIX_TO_STRIP: ACTION_
- enum ActionType {
- ACTION_NONE = 0,
- // Confirm infobar
- ACTION_OK = 1,
- ACTION_CANCEL = 2,
- // Translate infobar
- ACTION_TRANSLATE = 3,
- ACTION_TRANSLATE_SHOW_ORIGINAL = 4,
- };
-
- explicit InfoBarAndroid(std::unique_ptr<infobars::InfoBarDelegate> delegate);
- ~InfoBarAndroid() override;
-
- // InfoBar:
- virtual base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
- JNIEnv* env) = 0;
-
- virtual void SetJavaInfoBar(
- const base::android::JavaRef<jobject>& java_info_bar);
- const base::android::JavaRef<jobject>& GetJavaInfoBar();
- bool HasSetJavaInfoBar() const;
-
- // Tells the Java-side counterpart of this InfoBar to point to the replacement
- // InfoBar instead of this one.
- void ReassignJavaInfoBar(InfoBarAndroid* replacement);
-
- int GetInfoBarIdentifier(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj);
- virtual void OnLinkClicked(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj) {}
- void OnButtonClicked(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj,
- jint action);
- void OnCloseButtonClicked(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj);
-
- void CloseJavaInfoBar();
-
- // Maps from a Chromium ID (IDR_TRANSLATE) to a Drawable ID.
- int GetJavaIconId();
-
- // Acquire the java infobar from a different one. This is used to do in-place
- // replacements.
- virtual void PassJavaInfoBar(InfoBarAndroid* source) {}
-
- protected:
- // Derived classes must implement this method to process the corresponding
- // action.
- virtual void ProcessButton(int action) = 0;
-
- void CloseInfoBar();
- InfoBarAndroid* infobar_android() { return this; }
-
- private:
- base::android::ScopedJavaGlobalRef<jobject> java_info_bar_;
-
- DISALLOW_COPY_AND_ASSIGN(InfoBarAndroid);
-};
-
-} // namespace weblayer
-
-#endif // WEBLAYER_BROWSER_INFOBAR_ANDROID_H_
diff --git a/chromium/weblayer/browser/infobar_container_android.cc b/chromium/weblayer/browser/infobar_container_android.cc
index 368ab764ce8..6da65a200cf 100644
--- a/chromium/weblayer/browser/infobar_container_android.cc
+++ b/chromium/weblayer/browser/infobar_container_android.cc
@@ -8,10 +8,10 @@
#include "base/check.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
+#include "components/infobars/android/infobar_android.h"
#include "components/infobars/core/infobar.h"
#include "components/infobars/core/infobar_delegate.h"
#include "content/public/browser/web_contents.h"
-#include "weblayer/browser/infobar_android.h"
#include "weblayer/browser/infobar_service.h"
#include "weblayer/browser/java/jni/InfoBarContainer_jni.h"
@@ -50,7 +50,8 @@ void InfoBarContainerAndroid::PlatformSpecificAddInfoBar(
infobars::InfoBar* infobar,
size_t position) {
DCHECK(infobar);
- InfoBarAndroid* android_bar = static_cast<InfoBarAndroid*>(infobar);
+ infobars::InfoBarAndroid* android_bar =
+ static_cast<infobars::InfoBarAndroid*>(infobar);
if (!android_bar) {
// TODO(bulach): CLANK: implement other types of InfoBars.
NOTIMPLEMENTED() << "CLANK: infobar identifier "
@@ -61,7 +62,8 @@ void InfoBarContainerAndroid::PlatformSpecificAddInfoBar(
AttachJavaInfoBar(android_bar);
}
-void InfoBarContainerAndroid::AttachJavaInfoBar(InfoBarAndroid* android_bar) {
+void InfoBarContainerAndroid::AttachJavaInfoBar(
+ infobars::InfoBarAndroid* android_bar) {
if (android_bar->HasSetJavaInfoBar())
return;
JNIEnv* env = base::android::AttachCurrentThread();
@@ -92,13 +94,14 @@ void InfoBarContainerAndroid::AttachJavaInfoBar(InfoBarAndroid* android_bar) {
void InfoBarContainerAndroid::PlatformSpecificReplaceInfoBar(
infobars::InfoBar* old_infobar,
infobars::InfoBar* new_infobar) {
- static_cast<InfoBarAndroid*>(new_infobar)
- ->PassJavaInfoBar(static_cast<InfoBarAndroid*>(old_infobar));
+ static_cast<infobars::InfoBarAndroid*>(new_infobar)
+ ->PassJavaInfoBar(static_cast<infobars::InfoBarAndroid*>(old_infobar));
}
void InfoBarContainerAndroid::PlatformSpecificRemoveInfoBar(
infobars::InfoBar* infobar) {
- InfoBarAndroid* android_infobar = static_cast<InfoBarAndroid*>(infobar);
+ infobars::InfoBarAndroid* android_infobar =
+ static_cast<infobars::InfoBarAndroid*>(infobar);
android_infobar->CloseJavaInfoBar();
}
diff --git a/chromium/weblayer/browser/infobar_container_android.h b/chromium/weblayer/browser/infobar_container_android.h
index 4069cf6b19e..7ad6203b7c2 100644
--- a/chromium/weblayer/browser/infobar_container_android.h
+++ b/chromium/weblayer/browser/infobar_container_android.h
@@ -16,9 +16,11 @@
#include "base/macros.h"
#include "components/infobars/core/infobar_container.h"
-namespace weblayer {
-
+namespace infobars {
class InfoBarAndroid;
+}
+
+namespace weblayer {
class InfoBarContainerAndroid : public infobars::InfoBarContainer {
public:
@@ -44,7 +46,7 @@ class InfoBarContainerAndroid : public infobars::InfoBarContainer {
// Create the Java equivalent of |android_bar| and add it to the java
// container.
- void AttachJavaInfoBar(InfoBarAndroid* android_bar);
+ void AttachJavaInfoBar(infobars::InfoBarAndroid* android_bar);
// We're owned by the java infobar, need to use a weak ref so it can destroy
// us.
diff --git a/chromium/weblayer/browser/infobar_service.cc b/chromium/weblayer/browser/infobar_service.cc
index 37af3091f35..a2e60fe6e29 100644
--- a/chromium/weblayer/browser/infobar_service.cc
+++ b/chromium/weblayer/browser/infobar_service.cc
@@ -4,6 +4,14 @@
#include "weblayer/browser/infobar_service.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include "base/bind.h"
+#include "components/infobars/android/confirm_infobar.h"
+#include "weblayer/browser/android/resource_mapper.h"
+#endif
+
namespace weblayer {
InfoBarService::InfoBarService(content::WebContents* web_contents)
@@ -11,6 +19,20 @@ InfoBarService::InfoBarService(content::WebContents* web_contents)
InfoBarService::~InfoBarService() {}
+#if defined(OS_ANDROID)
+std::unique_ptr<infobars::InfoBar> InfoBarService::CreateConfirmInfoBar(
+ std::unique_ptr<ConfirmInfoBarDelegate> delegate) {
+ return std::make_unique<infobars::ConfirmInfoBar>(std::move(delegate),
+ GetResourceIdMapper());
+}
+
+// static
+infobars::InfoBarAndroid::ResourceIdMapper
+InfoBarService::GetResourceIdMapper() {
+ return base::BindRepeating(&MapToJavaDrawableId);
+}
+#endif // if defined(OS_ANDROID)
+
void InfoBarService::WebContentsDestroyed() {
// The WebContents is going away; be aggressively paranoid and delete
// ourselves lest other parts of the system attempt to add infobars or use
diff --git a/chromium/weblayer/browser/infobar_service.h b/chromium/weblayer/browser/infobar_service.h
index 95cb1ec184b..1d6f0a14c36 100644
--- a/chromium/weblayer/browser/infobar_service.h
+++ b/chromium/weblayer/browser/infobar_service.h
@@ -13,6 +13,10 @@
#include "components/infobars/content/content_infobar_manager.h"
#include "content/public/browser/web_contents_user_data.h"
+#if defined(OS_ANDROID)
+#include "components/infobars/android/infobar_android.h"
+#endif
+
namespace content {
class WebContents;
}
@@ -33,6 +37,10 @@ class InfoBarService : public infobars::ContentInfoBarManager,
std::unique_ptr<infobars::InfoBar> CreateConfirmInfoBar(
std::unique_ptr<ConfirmInfoBarDelegate> delegate) override;
+#if defined(OS_ANDROID)
+ static infobars::InfoBarAndroid::ResourceIdMapper GetResourceIdMapper();
+#endif
+
protected:
explicit InfoBarService(content::WebContents* web_contents);
diff --git a/chromium/weblayer/browser/insecure_form_controller_client.cc b/chromium/weblayer/browser/insecure_form_controller_client.cc
new file mode 100644
index 00000000000..9b7fed0b16d
--- /dev/null
+++ b/chromium/weblayer/browser/insecure_form_controller_client.cc
@@ -0,0 +1,47 @@
+// Copyright 2020 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 "weblayer/browser/insecure_form_controller_client.h"
+
+#include "content/public/browser/web_contents.h"
+#include "weblayer/browser/i18n_util.h"
+
+namespace weblayer {
+
+// static
+std::unique_ptr<security_interstitials::MetricsHelper>
+InsecureFormControllerClient::GetMetricsHelper(const GURL& url) {
+ security_interstitials::MetricsHelper::ReportDetails settings;
+ settings.metric_prefix = "insecure_form";
+ return std::make_unique<security_interstitials::MetricsHelper>(url, settings,
+ nullptr);
+}
+
+InsecureFormControllerClient::InsecureFormControllerClient(
+ content::WebContents* web_contents,
+ const GURL& form_target_url)
+ : SecurityInterstitialControllerClient(
+ web_contents,
+ GetMetricsHelper(form_target_url),
+ nullptr, /* prefs */
+ i18n::GetApplicationLocale(),
+ GURL("about:blank") /* default_safe_page */),
+ web_contents_(web_contents) {}
+
+InsecureFormControllerClient::~InsecureFormControllerClient() = default;
+
+void InsecureFormControllerClient::GoBack() {
+ SecurityInterstitialControllerClient::GoBackAfterNavigationCommitted();
+}
+
+void InsecureFormControllerClient::Proceed() {
+ // TODO(crbug.com/1093955): The simple reload logic means the interstitial is
+ // bypassed with any reload (e.g. F5), ideally this shouldn't be the case.
+
+ // We don't check for repost on the proceed reload since the interstitial
+ // explains this will submit the form.
+ web_contents_->GetController().Reload(content::ReloadType::NORMAL, false);
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/insecure_form_controller_client.h b/chromium/weblayer/browser/insecure_form_controller_client.h
new file mode 100644
index 00000000000..e8c80c58f01
--- /dev/null
+++ b/chromium/weblayer/browser/insecure_form_controller_client.h
@@ -0,0 +1,43 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_INSECURE_FORM_CONTROLLER_CLIENT_H_
+#define WEBLAYER_BROWSER_INSECURE_FORM_CONTROLLER_CLIENT_H_
+
+#include "components/security_interstitials/content/security_interstitial_controller_client.h"
+#include "components/security_interstitials/core/metrics_helper.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace weblayer {
+
+// A stripped-down version of the class by the same name in
+// //chrome/browser/ssl, which provides basic functionality for interacting with
+// the insecure form interstitial.
+class InsecureFormControllerClient
+ : public security_interstitials::SecurityInterstitialControllerClient {
+ public:
+ static std::unique_ptr<security_interstitials::MetricsHelper>
+ GetMetricsHelper(const GURL& url);
+
+ InsecureFormControllerClient(content::WebContents* web_contents,
+ const GURL& form_target_url);
+ InsecureFormControllerClient(const InsecureFormControllerClient&) = delete;
+ InsecureFormControllerClient& operator=(const InsecureFormControllerClient&) =
+ delete;
+ ~InsecureFormControllerClient() override;
+
+ // security_interstitials::SecurityInterstitialControllerClient:
+ void GoBack() override;
+ void Proceed() override;
+
+ private:
+ content::WebContents* web_contents_;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_INSECURE_FORM_CONTROLLER_CLIENT_H_
diff --git a/chromium/weblayer/browser/java/AndroidManifest.xml b/chromium/weblayer/browser/java/AndroidManifest.xml
new file mode 100644
index 00000000000..20cd3a9dd9b
--- /dev/null
+++ b/chromium/weblayer/browser/java/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 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. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:dist="http://schemas.android.com/apk/distribution"
+ featureSplit="weblayer">
+
+ <!-- Due to b/164116603 fusing is false for now. Once that bug is fixed,
+ the WebLayer module should be fused. -->
+ <dist:module
+ dist:onDemand="false">
+ <dist:fusing dist:include="false" />
+ </dist:module>
+
+ <application />
+</manifest>
diff --git a/chromium/weblayer/browser/java/BUILD.gn b/chromium/weblayer/browser/java/BUILD.gn
index 38cdda128ce..45c20a4d642 100644
--- a/chromium/weblayer/browser/java/BUILD.gn
+++ b/chromium/weblayer/browser/java/BUILD.gn
@@ -7,21 +7,26 @@ import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
import("//weblayer/variables.gni")
+_bundle_utils_output =
+ "$target_gen_dir/org/chromium/weblayer_private/WebLayerBundleUtils.java"
+
+jinja_template("weblayer_bundle_utils") {
+ input = "WebLayerBundleUtils.java.jinja2"
+ output = _bundle_utils_output
+ variables = "weblayer_in_split=$weblayer_in_split"
+}
+
android_resources("weblayer_resources") {
sources = [
- "res/drawable/weblayer_infobar_wrapper_bg.xml",
"res/drawable/weblayer_tab_indicator.xml",
"res/layout/site_settings_layout.xml",
"res/layout/weblayer_infobar_translate_compact_content.xml",
- "res/layout/weblayer_infobar_translate_tab_content.xml",
- "res/layout/weblayer_translate_menu_item.xml",
- "res/layout/weblayer_translate_menu_item_checked.xml",
"res/layout/weblayer_url_bar.xml",
"res/values/colors.xml",
"res/values/dimens.xml",
"res/values/styles.xml",
]
- custom_package = "org.chromium.weblayer_private"
+ create_srcjar = false
deps = [
":weblayer_strings_grd",
"//components/blocked_content/android:java_resources",
@@ -35,11 +40,18 @@ android_resources("weblayer_resources") {
"//components/page_info/android:java_resources",
"//components/permissions/android:java_resources",
"//components/translate/content/android:java_resources",
- "//third_party/android_deps:com_google_android_material_material_java",
+ "//third_party/android_deps:material_design_java",
"//weblayer:components_java_strings",
]
}
+# This resource target is kept in the base module when WebLayer is in a split,
+# and allows WebLayer to call onResourcesLoaded() on resources shared with
+# WebView.
+android_resources("weblayer_base_module_resources") {
+ custom_package = "org.chromium.weblayer_private.base"
+}
+
generate_product_config_srcjar("weblayer_product_config") {
java_package = weblayer_product_config_java_package
}
@@ -51,6 +63,7 @@ java_cpp_template("resource_id_javagen") {
"//components/resources/android/blocked_content_resource_id.h",
"//components/resources/android/page_info_resource_id.h",
"//components/resources/android/permissions_resource_id.h",
+ "//components/resources/android/sms_resource_id.h",
]
}
@@ -65,8 +78,6 @@ java_strings_grd("weblayer_strings_grd") {
java_cpp_enum("generated_enums") {
sources = [
"//weblayer/browser/controls_visibility_reason.h",
- "//weblayer/browser/infobar_android.h",
- "//weblayer/browser/translate_utils.h",
"//weblayer/public/download.h",
"//weblayer/public/navigation.h",
"//weblayer/public/new_tab_delegate.h",
@@ -74,6 +85,16 @@ java_cpp_enum("generated_enums") {
]
}
+android_library("base_module_java") {
+ sources =
+ [ "org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java" ]
+ deps = [
+ ":weblayer_base_module_resources",
+ "//base:base_java",
+ ]
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+}
+
android_library("java") {
sources = [
"org/chromium/weblayer_private/ActionModeCallback.java",
@@ -84,7 +105,6 @@ android_library("java") {
"org/chromium/weblayer_private/BrowserImpl.java",
"org/chromium/weblayer_private/BrowserViewController.java",
"org/chromium/weblayer_private/ChildProcessServiceImpl.java",
- "org/chromium/weblayer_private/ConfirmInfoBar.java",
"org/chromium/weblayer_private/ContentViewRenderView.java",
"org/chromium/weblayer_private/CookieManagerImpl.java",
"org/chromium/weblayer_private/CrashReporterControllerImpl.java",
@@ -92,16 +112,14 @@ android_library("java") {
"org/chromium/weblayer_private/DownloadImpl.java",
"org/chromium/weblayer_private/ErrorPageCallbackProxy.java",
"org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java",
+ "org/chromium/weblayer_private/FaviconCallbackProxy.java",
"org/chromium/weblayer_private/FragmentAndroidPermissionDelegate.java",
"org/chromium/weblayer_private/FragmentWindowAndroid.java",
"org/chromium/weblayer_private/FullscreenCallbackProxy.java",
- "org/chromium/weblayer_private/InfoBar.java",
- "org/chromium/weblayer_private/InfoBarCompactLayout.java",
+ "org/chromium/weblayer_private/FullscreenToast.java",
+ "org/chromium/weblayer_private/GoogleAccountsCallbackProxy.java",
"org/chromium/weblayer_private/InfoBarContainer.java",
- "org/chromium/weblayer_private/InfoBarContainerLayout.java",
"org/chromium/weblayer_private/InfoBarContainerView.java",
- "org/chromium/weblayer_private/InfoBarUiItem.java",
- "org/chromium/weblayer_private/InfoBarWrapper.java",
"org/chromium/weblayer_private/IntentUtils.java",
"org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java",
"org/chromium/weblayer_private/LocaleChangedBroadcastReceiver.java",
@@ -116,42 +134,41 @@ android_library("java") {
"org/chromium/weblayer_private/ProfileManager.java",
"org/chromium/weblayer_private/RemoteFragmentImpl.java",
"org/chromium/weblayer_private/SiteSettingsFragmentImpl.java",
- "org/chromium/weblayer_private/SwipableOverlayView.java",
"org/chromium/weblayer_private/TabCallbackProxy.java",
"org/chromium/weblayer_private/TabImpl.java",
"org/chromium/weblayer_private/TranslateCompactInfoBar.java",
- "org/chromium/weblayer_private/TranslateMenu.java",
- "org/chromium/weblayer_private/TranslateMenuHelper.java",
- "org/chromium/weblayer_private/TranslateOptions.java",
- "org/chromium/weblayer_private/TranslateTabContent.java",
- "org/chromium/weblayer_private/TranslateTabLayout.java",
"org/chromium/weblayer_private/UrlBarControllerImpl.java",
"org/chromium/weblayer_private/WebContentsGestureStateTracker.java",
"org/chromium/weblayer_private/WebLayerAccessibilityUtil.java",
"org/chromium/weblayer_private/WebLayerExceptionFilter.java",
"org/chromium/weblayer_private/WebLayerFactoryImpl.java",
"org/chromium/weblayer_private/WebLayerImpl.java",
- "org/chromium/weblayer_private/WebLayerNotificationBuilder.java",
"org/chromium/weblayer_private/WebLayerNotificationChannels.java",
+ "org/chromium/weblayer_private/WebLayerNotificationWrapperBuilder.java",
"org/chromium/weblayer_private/WebLayerSiteSettingsClient.java",
"org/chromium/weblayer_private/WebLayerTabModalPresenter.java",
"org/chromium/weblayer_private/WebMessageReplyProxyImpl.java",
"org/chromium/weblayer_private/WebShareServiceFactory.java",
- "org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java",
"org/chromium/weblayer_private/metrics/MetricsServiceClient.java",
"org/chromium/weblayer_private/metrics/UmaUtils.java",
"org/chromium/weblayer_private/permissions/PermissionRequestUtils.java",
"org/chromium/weblayer_private/resources/ResourceMapper.java",
+ _bundle_utils_output,
]
+ resources_package = "org.chromium.weblayer_private"
deps = [
+ ":base_module_java",
":gms_bridge_java",
":interfaces_java",
+ ":weblayer_bundle_utils",
":weblayer_resources",
"//base:base_java",
"//base:jni_java",
"//components/autofill/android/provider:java",
+ "//components/browser_ui/banners/android:java",
"//components/browser_ui/client_certificate/android:java",
+ "//components/browser_ui/display_cutout/android:java",
"//components/browser_ui/http_auth/android:java",
"//components/browser_ui/media/android:java",
"//components/browser_ui/modaldialog/android:java",
@@ -159,10 +176,12 @@ android_library("java") {
"//components/browser_ui/settings/android:java",
"//components/browser_ui/share/android:java",
"//components/browser_ui/site_settings/android:java",
+ "//components/browser_ui/sms/android:java",
"//components/browser_ui/styles/android:java",
"//components/browser_ui/util/android:java",
"//components/browser_ui/webshare/android:java",
"//components/browser_ui/widget/android:java",
+ "//components/content_settings/android:content_settings_enums_java",
"//components/content_settings/android:java",
"//components/crash/android:handler_java",
"//components/crash/android:java",
@@ -176,6 +195,7 @@ android_library("java") {
"//components/embedder_support/android/metrics:java",
"//components/external_intents/android:java",
"//components/find_in_page/android:java",
+ "//components/infobars/android:infobar_android_enums_java",
"//components/infobars/android:java",
"//components/infobars/core:infobar_enums_java",
"//components/javascript_dialogs/android:java",
@@ -188,12 +208,13 @@ android_library("java") {
"//components/permissions/android:java",
"//components/safe_browsing/android:safe_browsing_java",
"//components/security_interstitials/content/android:java",
+ "//components/signin/core/browser:signin_enums_java",
"//components/spellcheck/browser/android:java",
+ "//components/translate/content/android:java",
+ "//components/translate/content/android:translate_android_enums_java",
"//components/url_formatter/android:url_formatter_java",
"//components/variations/android:variations_java",
"//components/version_info/android:version_constants_java",
- "//components/webapk/android/libs/client:java",
- "//components/webapk/android/libs/common:java",
"//components/webrtc/android:java",
"//content/public/android:content_java",
"//mojo/public/java:bindings_java",
@@ -201,16 +222,19 @@ android_library("java") {
"//services/network/public/mojom:cookies_mojom_java",
"//services/network/public/mojom:mojom_java",
"//services/service_manager/public/java:service_manager_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
"//third_party/android_deps:androidx_appcompat_appcompat_java",
"//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
"//third_party/android_deps:androidx_core_core_java",
"//third_party/android_deps:androidx_fragment_fragment_java",
+ "//third_party/android_deps:androidx_media_media_java",
"//third_party/android_deps:androidx_preference_preference_java",
- "//third_party/android_deps:com_google_android_material_material_java",
+ "//third_party/android_deps:material_design_java",
"//third_party/blink/public/mojom:android_mojo_bindings_java",
"//ui/android:ui_full_java",
"//ui/android:ui_java",
"//url:gurl_java",
+ "//url:origin_java",
]
srcjar_deps = [
":generated_enums",
@@ -236,7 +260,7 @@ android_resources("weblayer_test_resources") {
"res_test/layout/test_layout.xml",
"res_test/values/values.xml",
]
- custom_package = "org.chromium.weblayer_private.test"
+ create_srcjar = false
}
android_library("test_java") {
@@ -245,23 +269,34 @@ android_library("test_java") {
"org/chromium/weblayer_private/test/TestInfoBar.java",
"org/chromium/weblayer_private/test/TestWebLayerImpl.java",
]
+ resources_package = "org.chromium.weblayer_private.test"
deps = [
":interfaces_java",
":java",
":weblayer_test_resources",
+ "//base:base_java",
"//base:jni_java",
+ "//components/infobars/android:java",
"//components/location/android:location_java",
"//components/permissions/android:java",
"//content/public/test/android:content_java_test_support",
"//net/android:net_java",
"//services/device/public/java:geolocation_java",
"//services/device/public/java:geolocation_java_test_support",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
"//ui/android:ui_full_java",
]
srcjar_deps = [ ":test_aidl" ]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}
+generate_jni_registration("test_weblayer_jni_registration") {
+ testonly = true
+ targets = [ ":test_java" ]
+ header_output = "$target_gen_dir/$target_name.h"
+ namespace = "weblayer_test"
+}
+
generate_jni("test_jni") {
testonly = true
sources = [
@@ -275,14 +310,14 @@ generate_jni("jni") {
"org/chromium/weblayer_private/AutocompleteSchemeClassifierImpl.java",
"org/chromium/weblayer_private/BrowserControlsContainerView.java",
"org/chromium/weblayer_private/BrowserImpl.java",
- "org/chromium/weblayer_private/ConfirmInfoBar.java",
"org/chromium/weblayer_private/ContentViewRenderView.java",
"org/chromium/weblayer_private/CookieManagerImpl.java",
"org/chromium/weblayer_private/DownloadCallbackProxy.java",
"org/chromium/weblayer_private/DownloadImpl.java",
"org/chromium/weblayer_private/ErrorPageCallbackProxy.java",
+ "org/chromium/weblayer_private/FaviconCallbackProxy.java",
"org/chromium/weblayer_private/FullscreenCallbackProxy.java",
- "org/chromium/weblayer_private/InfoBar.java",
+ "org/chromium/weblayer_private/GoogleAccountsCallbackProxy.java",
"org/chromium/weblayer_private/InfoBarContainer.java",
"org/chromium/weblayer_private/LocaleChangedBroadcastReceiver.java",
"org/chromium/weblayer_private/MediaStreamManager.java",
@@ -315,6 +350,7 @@ android_library("interfaces_java") {
"org/chromium/weblayer_private/interfaces/CookieChangeCause.java",
"org/chromium/weblayer_private/interfaces/DownloadError.java",
"org/chromium/weblayer_private/interfaces/DownloadState.java",
+ "org/chromium/weblayer_private/interfaces/GoogleAccountServiceType.java",
"org/chromium/weblayer_private/interfaces/LoadError.java",
"org/chromium/weblayer_private/interfaces/NavigateParams.java",
"org/chromium/weblayer_private/interfaces/NavigationState.java",
@@ -375,8 +411,11 @@ android_aidl("aidl") {
"org/chromium/weblayer_private/interfaces/IDownload.aidl",
"org/chromium/weblayer_private/interfaces/IDownloadCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/IErrorPageCallbackClient.aidl",
+ "org/chromium/weblayer_private/interfaces/IFaviconFetcher.aidl",
+ "org/chromium/weblayer_private/interfaces/IFaviconFetcherClient.aidl",
"org/chromium/weblayer_private/interfaces/IFindInPageCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/IFullscreenCallbackClient.aidl",
+ "org/chromium/weblayer_private/interfaces/IGoogleAccountsCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/IMediaCaptureCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/INavigation.aidl",
"org/chromium/weblayer_private/interfaces/INavigationController.aidl",
diff --git a/chromium/weblayer/browser/java/DEPS b/chromium/weblayer/browser/java/DEPS
index 819b5a6c915..75b1b714394 100644
--- a/chromium/weblayer/browser/java/DEPS
+++ b/chromium/weblayer/browser/java/DEPS
@@ -11,11 +11,13 @@ include_rules = [
"+components/webapk/android/libs",
"+services/device/public/java/src/org/chromium/device/geolocation",
- # WebLayerNotificationBuilder should be used for all notifications.
- "-components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationBuilder.java",
+ # WebLayerNotificationWrapperBuilder should be used for all notifications.
+ "-components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapperCompatBuilder.java",
+ "-components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapperStandardBuilder.java",
]
specific_include_rules = {
- "WebLayerNotificationBuilder.java": [
- "+components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationBuilder.java",
+ "WebLayerNotificationWrapperBuilder.java": [
+ "+components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapperCompatBuilder.java",
+ "+components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapperStandardBuilder.java",
]
}
diff --git a/chromium/weblayer/browser/java/ResourceId.template b/chromium/weblayer/browser/java/ResourceId.template
index 1e16c782f49..ed370063cb5 100644
--- a/chromium/weblayer/browser/java/ResourceId.template
+++ b/chromium/weblayer/browser/java/ResourceId.template
@@ -14,6 +14,7 @@ class ResourceId {
#include "components/resources/android/blocked_content_resource_id.h"
#include "components/resources/android/page_info_resource_id.h"
#include "components/resources/android/permissions_resource_id.h"
+#include "components/resources/android/sms_resource_id.h"
};
return resourceList;
}
diff --git a/chromium/weblayer/browser/java/WebLayerBundleUtils.java.jinja2 b/chromium/weblayer/browser/java/WebLayerBundleUtils.java.jinja2
new file mode 100644
index 00000000000..4b03d9672c6
--- /dev/null
+++ b/chromium/weblayer/browser/java/WebLayerBundleUtils.java.jinja2
@@ -0,0 +1,9 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.weblayer_private;
+
+public final class WebLayerBundleUtils {
+ public static final boolean IS_WEBLAYER_IN_SPLIT = {{ weblayer_in_split }};
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java
index ce10368c02c..454fb68b70c 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java
@@ -11,11 +11,14 @@ import android.view.View;
import android.view.ViewParent;
import android.widget.FrameLayout;
+import androidx.annotation.Nullable;
+
import org.chromium.base.MathUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.BrowserControlsState;
import org.chromium.ui.base.EventOffsetHandler;
import org.chromium.ui.resources.dynamics.ViewResourceAdapter;
@@ -58,8 +61,27 @@ class BrowserControlsContainerView extends FrameLayout {
private static final long SYSTEM_UI_VIEWPORT_UPDATE_DELAY_MS = 500;
+ private static final int DEFAULT_LAST_SHOWN_AMOUNT = -1;
+
+ /** Stores the state needed to reconstruct offsets after recreating this class. */
+ /* package */ static class State {
+ private final int mControlsOffset;
+ private final int mContentOffset;
+
+ private State(int controlsOffset, int contentOffset) {
+ mControlsOffset = controlsOffset;
+ mContentOffset = contentOffset;
+ }
+ }
+
+ private final Delegate mDelegate;
private final boolean mIsTop;
+ // The state returned by a previous BrowserControlsContainerView instance's getState() method.
+ // This is saved rather than directly applied because layout needs to occur before we can apply
+ // the offsets.
+ private State mSavedState;
+
private long mNativeBrowserControlsContainerView;
private ViewResourceAdapter mViewResourceAdapter;
@@ -68,7 +90,7 @@ class BrowserControlsContainerView extends FrameLayout {
private int mLastWidth;
private int mLastHeight;
- // view from the client.
+ // View from the client.
private View mView;
private ContentViewRenderView mContentViewRenderView;
@@ -87,41 +109,70 @@ class BrowserControlsContainerView extends FrameLayout {
// bottom-controls, the value ranges from 0 (completely shown) to height (completely hidden).
private int mControlsOffset;
+ // Stores how much of the controls in pixels is visible when a view is set. This does NOT get
+ // set to 0 when you remove a view; it always stores the most recent control visibility amount
+ // as of the last time a view was actually set, or a default value. This is used to help mimic
+ // the positioning behavior of the renderer.
+ private int mLastShownAmountWithView = DEFAULT_LAST_SHOWN_AMOUNT;
+
+ // The minimum height that the controls should collapse to. Only used for top controls.
+ private int mMinHeight;
+
+ // Whether the controls should only expand when the page is scrolled to the top. Only used for
+ // top controls.
+ private boolean mOnlyExpandControlsAtPageTop;
+
+ // Set to true if changes to the controls height or offset should be animated.
+ private boolean mShouldAnimate;
+
// Set to true if |mView| is hidden because the user has scrolled or triggered some action such
// that mView is not visible. While |mView| is not visible if this is true, the bitmap from
// |mView| may be partially visible.
private boolean mInScroll;
+ // Set to true while we are animating the controls off the screen after removing them.
+ private boolean mAnimatingOut;
+
private boolean mIsFullscreen;
// Used to delay processing fullscreen requests.
private Runnable mSystemUiFullscreenResizeRunnable;
- private final Listener mListener;
-
- public interface Listener {
- /**
- * Called when the browser-controls are either completely showing, or completely hiding.
- */
- public void onBrowserControlsCompletelyShownOrHidden();
- }
-
- // Used to delay updating the image for the layer.
+ // Used to delay updating the image for the layer.
private final Runnable mRefreshResourceIdRunnable = () -> {
- if (mView == null) return;
+ if (mView == null || mViewResourceAdapter == null) return;
BrowserControlsContainerViewJni.get().updateControlsResource(
mNativeBrowserControlsContainerView);
};
+ // Used to delay hiding the controls.
+ private final Runnable mHideControlsRunnable = this::hideControlsNow;
+
+ // Used to delay showing the controls.
+ private final Runnable mShowControlsRunnable = this::showControlsNow;
+
+ public interface Delegate {
+ /**
+ * Requests that the page height be recalculated due to browser controls height changes.
+ */
+ void refreshPageHeight();
+
+ /**
+ * Requests that the browser controls visibility state be changed.
+ */
+ void setAnimationConstraint(@BrowserControlsState int constraint);
+ }
+
BrowserControlsContainerView(Context context, ContentViewRenderView contentViewRenderView,
- Listener listener, boolean isTop) {
+ Delegate delegate, boolean isTop, @Nullable State savedState) {
super(context);
+ mDelegate = delegate;
mIsTop = isTop;
+ mSavedState = savedState;
mContentViewRenderView = contentViewRenderView;
mNativeBrowserControlsContainerView =
BrowserControlsContainerViewJni.get().createBrowserControlsContainerView(
this, contentViewRenderView.getNativeHandle(), isTop);
- mListener = listener;
}
public void setWebContents(WebContents webContents) {
@@ -135,7 +186,8 @@ class BrowserControlsContainerView extends FrameLayout {
}
public void destroy() {
- clearViewAndDestroyResources();
+ if (mIsTop) setAnimationsEnabled(false);
+ setView(null);
BrowserControlsContainerViewJni.get().deleteBrowserControlsContainerView(
mNativeBrowserControlsContainerView);
cancelDelayedFullscreenRunnable();
@@ -172,7 +224,7 @@ class BrowserControlsContainerView extends FrameLayout {
*/
public int getContentHeightDelta() {
if (mView == null) return 0;
- return mIsTop ? mContentOffset : getHeight() - mControlsOffset;
+ return mIsTop ? mContentOffset : mLastHeight - mControlsOffset;
}
/**
@@ -180,15 +232,22 @@ class BrowserControlsContainerView extends FrameLayout {
*/
public boolean isControlVisible() {
// Don't check the visibility of the View itself as it's hidden while scrolling.
- return mView != null && Math.abs(mControlsOffset) != getHeight();
+ return mView != null && Math.abs(mControlsOffset) != mLastHeight;
+ }
+
+ public void setAnimationsEnabled(boolean animationsEnabled) {
+ assert mIsTop;
+ mShouldAnimate = animationsEnabled;
}
/**
- * Returns true if the controls are completely shown or completely hidden. A return value
- * of false indicates the controls are being moved.
+ * Returns true if the controls are completely expanded or completely collapsed.
+ * "Completely collapsed" does not necessarily mean hidden; the controls could be at their min
+ * height, in which case this would return true. A return value of false indicates the controls
+ * are being moved.
*/
- public boolean isCompletelyShownOrHidden() {
- return mControlsOffset == 0 || Math.abs(mControlsOffset) == getHeight();
+ public boolean isCompletelyExpandedOrCollapsed() {
+ return mControlsOffset == 0 || Math.abs(mControlsOffset) == mLastHeight - mMinHeight;
}
/**
@@ -196,56 +255,89 @@ class BrowserControlsContainerView extends FrameLayout {
*/
public void setView(View view) {
if (mView == view) return;
- clearViewAndDestroyResources();
+
+ if (mView != null && mView.getParent() == this) removeView(mView);
mView = view;
+
if (mView == null) {
- setControlsOffset(0, 0);
+ // If we're animating out the old view, leave the cc::Layer in place so it's visible
+ // during the animation, and set our visibility to HIDDEN, which will cause
+ // BrowserControlsOffsetManager to start an animation off the screen. getMinHeight()
+ // will return 0 while mAnimatingOut is true, so call reportHeightChange() to tell the
+ // renderer to grab the potentially new height.
+ if (mShouldAnimate && mControlsOffset != -mLastHeight) {
+ assert mIsTop; // mShouldAnimate should only be true for top controls.
+ mAnimatingOut = true;
+ reportHeightChange();
+ mDelegate.setAnimationConstraint(BrowserControlsState.HIDDEN);
+ mDelegate.refreshPageHeight();
+ } else {
+ destroyLayer();
+ }
return;
}
+
+ mAnimatingOut = false;
+ destroyLayer();
addView(view,
new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.UNSPECIFIED_GRAVITY));
- if (getWidth() > 0 && getHeight() > 0) {
- view.layout(0, 0, getWidth(), getHeight());
- createAdapterAndLayer();
- }
- if (mIsFullscreen) hideControls();
+ // The controls will be positioned in onLayout, which will result in showControls or
+ // hideControls being called. hideControls may delay the hide by a frame, resulting in the
+ // View flashing during the current frame. To work around this, we hide the controls here.
+ // showControls will also delay the showing by a frame, but that doesn't cause a flash
+ // because the bitmap will be visible until the setVisibility call completes.
+ hideControlsNow();
+ mContentViewRenderView.removeCallbacks(mShowControlsRunnable);
+ mDelegate.setAnimationConstraint(BrowserControlsState.BOTH);
+ }
+
+ public View getView() {
+ return mView;
}
/**
- * Does cleanup necessary when mView is to be removed.
- * In general prefer calling setView(). This is really an implementation detail of setView()
- * and destroy().
+ * Sets the minimum height the controls can collapse to.
+ * Only valid for top controls.
*/
- private void clearViewAndDestroyResources() {
- if (mView == null) return;
- if (mView.getParent() == this) removeView(mView);
- // TODO: need some sort of destroy to drop reference.
- mViewResourceAdapter = null;
- BrowserControlsContainerViewJni.get().deleteControlsLayer(
- mNativeBrowserControlsContainerView);
- mContentViewRenderView.getResourceManager().getDynamicResourceLoader().unregisterResource(
- getResourceId());
- mView = null;
- mLastWidth = mLastHeight = 0;
+ public void setMinHeight(int minHeight) {
+ assert mIsTop;
+ if (mMinHeight == minHeight) return;
+ mMinHeight = minHeight;
+ reportHeightChange();
}
- public View getView() {
- return mView;
+ /**
+ * Sets whether the controls should only expand at the top of the page contents.
+ * Only valid for top controls.
+ */
+ public void setOnlyExpandControlsAtPageTop(boolean onlyExpandControlsAtPageTop) {
+ mOnlyExpandControlsAtPageTop = onlyExpandControlsAtPageTop;
}
/**
* Called from ViewAndroidDelegate, see it for details.
*/
public void onOffsetsChanged(int controlsOffsetY, int contentOffsetY) {
- if (mView == null) return;
- if (mIsFullscreen) return;
- if (controlsOffsetY == 0) {
- finishScroll(contentOffsetY);
- return;
+ // Delete the cc::Layer if we reached the end of the animation off the screen.
+ if (mAnimatingOut && controlsOffsetY == -mLastHeight) {
+ mAnimatingOut = false;
+ destroyLayer();
+ reportHeightChange();
+ // Request a layout so onLayout can update the saved dimensions now that the
+ // layer has finished animating.
+ requestLayout();
}
- if (!mInScroll) prepareForScroll();
+
+ if (mIsFullscreen) return;
setControlsOffset(controlsOffsetY, contentOffsetY);
+ if (mControlsOffset == 0
+ || (mIsTop && getMinHeight() > 0
+ && mControlsOffset == -mLastHeight + getMinHeight())) {
+ finishScroll();
+ } else if (!mInScroll) {
+ prepareForScroll();
+ }
}
@SuppressLint("NewApi") // Used on O+, invalidateChildInParent used for previous versions.
@@ -264,38 +356,57 @@ class BrowserControlsContainerView extends FrameLayout {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- if (mView == null) return;
+ if (mAnimatingOut) return;
int width = right - left;
int height = bottom - top;
boolean heightChanged = height != mLastHeight;
if (!heightChanged && width == mLastWidth) return;
+ int prevHeight = mLastHeight;
mLastWidth = width;
mLastHeight = height;
if (mLastWidth > 0 && mLastHeight > 0 && mViewResourceAdapter == null) {
createAdapterAndLayer();
- } else if (mViewResourceAdapter != null) {
- BrowserControlsContainerViewJni.get().setControlsSize(
- mNativeBrowserControlsContainerView, mLastWidth, mLastHeight);
- if (mWebContents != null) mWebContents.notifyBrowserControlsHeightChanged();
- if (heightChanged) {
- // When the height changes cc doesn't generate a new frame, which means this code
- // must process the change now. If cc generated a new frame, it would likely be at
- // the wrong size.
- if (mControlsOffset == 0) {
- // The controls are completely visible.
- onOffsetsChanged(0, height);
+ if (mLastShownAmountWithView == DEFAULT_LAST_SHOWN_AMOUNT && mSavedState != null) {
+ // If there wasn't a View before and we have non-empty saved state from a previous
+ // BrowserControlsContainerView instance, apply those saved offsets now. We can't
+ // rely on BrowserControlsOffsetManager to notify us of the correct location as we
+ // usually do because it only notifies us when offsets change, but it likely didn't
+ // get destroyed when the BrowserFragment got recreated, so it won't notify us
+ // because it thinks we already have the correct offsets.
+ onOffsetsChanged(mSavedState.mControlsOffset, mSavedState.mContentOffset);
+ } else {
+ // Ideally we'd leave the controls hidden and wait for BrowserControlsOffsetManager
+ // to tell us where it wants them, but it communicates with us via frame metadata
+ // that is generated when the renderer's compositor submits a frame to viz, which is
+ // paused during page loads. Because of this, we might not get positioning
+ // information from the renderer for several seconds during page loads, so we need
+ // to attempt to position the controls ourselves here.
+ int targetShownAmount;
+ if (mShouldAnimate) {
+ // If animations are enabled, leave the amount of visible controls unchanged
+ // (e.g. hide them if there weren't previously controls or if they were hidden
+ // before).
+ targetShownAmount = mIsTop ? (prevHeight + mControlsOffset)
+ : (prevHeight - mControlsOffset);
} else {
- // The controls are partially (and possibly completely) hidden. Snap to
- // completely hidden.
- if (mIsTop) {
- onOffsetsChanged(-height, height);
- } else {
- onOffsetsChanged(height, 0);
- }
+ // If animations are disabled, restore the positioning the controls had the last
+ // time they were non-null. This mimics the behavior of
+ // BrowserControlsOffsetManager in the renderer.
+ targetShownAmount = (mLastShownAmountWithView == DEFAULT_LAST_SHOWN_AMOUNT)
+ ? height
+ : mLastShownAmountWithView;
}
+ onOffsetsChanged(
+ mIsTop ? (targetShownAmount - height) : (height - targetShownAmount),
+ mIsTop ? targetShownAmount : 0);
}
+ mSavedState = null;
+ } else if (mViewResourceAdapter != null) {
+ BrowserControlsContainerViewJni.get().setControlsSize(
+ mNativeBrowserControlsContainerView, mLastWidth, mLastHeight);
}
+ if (heightChanged) reportHeightChange();
}
@Override
@@ -306,6 +417,10 @@ class BrowserControlsContainerView extends FrameLayout {
cancelDelayedFullscreenRunnable();
}
+ /* package */ State getState() {
+ return new State(mControlsOffset, mContentOffset);
+ }
+
private void cancelDelayedFullscreenRunnable() {
if (mSystemUiFullscreenResizeRunnable == null) return;
removeCallbacks(mSystemUiFullscreenResizeRunnable);
@@ -336,38 +451,41 @@ class BrowserControlsContainerView extends FrameLayout {
// the layer is created and actually shown. Chrome for Android does the same thing.
BrowserControlsContainerViewJni.get().createControlsLayer(
mNativeBrowserControlsContainerView, getResourceId());
- mLastWidth = getWidth();
- mLastHeight = getHeight();
BrowserControlsContainerViewJni.get().setControlsSize(
mNativeBrowserControlsContainerView, mLastWidth, mLastHeight);
- if (mIsFullscreen) {
- setFullscreenControlsOffset();
- } else {
- setControlsOffset(0, mLastHeight);
- }
}
- private void finishScroll(int contentOffsetY) {
- mInScroll = false;
- setControlsOffset(0, contentOffsetY);
- if (BrowserControlsContainerViewJni.get().shouldDelayVisibilityChange()) {
- mContentViewRenderView.postOnAnimation(() -> showControls());
- } else {
- showControls();
- }
+ /**
+ * Destroys the cc::Layer containing the bitmap copy of the View.
+ */
+ private void destroyLayer() {
+ if (mViewResourceAdapter == null) return;
+ // TODO: need some sort of destroy to drop reference.
+ mViewResourceAdapter = null;
+ BrowserControlsContainerViewJni.get().deleteControlsLayer(
+ mNativeBrowserControlsContainerView);
+ mContentViewRenderView.getResourceManager().getDynamicResourceLoader().unregisterResource(
+ getResourceId());
}
private void setControlsOffset(int controlsOffsetY, int contentOffsetY) {
// This function is called asynchronously from the gpu, and may be out of sync with the
// current values.
if (mIsTop) {
- mControlsOffset = MathUtils.clamp(controlsOffsetY, -getHeight(), 0);
+ // Don't snap to min-height because the controls could be animating in from a
+ // previously lower min-height.
+ mControlsOffset = MathUtils.clamp(controlsOffsetY, -mLastHeight, 0);
} else {
- mControlsOffset = MathUtils.clamp(controlsOffsetY, 0, getHeight());
+ mControlsOffset = MathUtils.clamp(controlsOffsetY, 0, mLastHeight);
}
- mContentOffset = MathUtils.clamp(contentOffsetY, 0, getHeight());
- if (isCompletelyShownOrHidden()) {
- mListener.onBrowserControlsCompletelyShownOrHidden();
+ mContentOffset = MathUtils.clamp(contentOffsetY, 0, mLastHeight);
+
+ if (mView != null) {
+ mLastShownAmountWithView =
+ mIsTop ? (mLastHeight + mControlsOffset) : (mLastHeight - mControlsOffset);
+ }
+ if (isCompletelyExpandedOrCollapsed()) {
+ mDelegate.refreshPageHeight();
}
if (mIsTop) {
BrowserControlsContainerViewJni.get().setTopControlsOffset(
@@ -378,21 +496,56 @@ class BrowserControlsContainerView extends FrameLayout {
}
}
+ private void reportHeightChange() {
+ if (mWebContents != null) {
+ mWebContents.notifyBrowserControlsHeightChanged();
+ }
+ }
+
private void prepareForScroll() {
mInScroll = true;
+ hideControls();
+ }
+
+ private void finishScroll() {
+ mInScroll = false;
+ showControls();
+ }
+
+ private void hideControls() {
if (BrowserControlsContainerViewJni.get().shouldDelayVisibilityChange()) {
- mContentViewRenderView.postOnAnimation(() -> hideControls());
+ mContentViewRenderView.postOnAnimation(mHideControlsRunnable);
} else {
- hideControls();
+ hideControlsNow();
}
}
- private void hideControls() {
- if (mView != null) mView.setVisibility(View.INVISIBLE);
+ private void hideControlsNow() {
+ if (mView != null) {
+ mView.setVisibility(View.INVISIBLE);
+ }
}
private void showControls() {
- if (mView != null) mView.setVisibility(View.VISIBLE);
+ if (BrowserControlsContainerViewJni.get().shouldDelayVisibilityChange()) {
+ mContentViewRenderView.postOnAnimation(mShowControlsRunnable);
+ } else {
+ showControlsNow();
+ }
+ }
+
+ private void showControlsNow() {
+ if (mView != null) {
+ if (mIsTop) {
+ mView.setTranslationY(mControlsOffset);
+ }
+ mView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @CalledByNative
+ /* package */ boolean shouldAnimateBrowserControlsHeightChanges() {
+ return mShouldAnimate;
}
@CalledByNative
@@ -401,6 +554,17 @@ class BrowserControlsContainerView extends FrameLayout {
}
@CalledByNative
+ private int getMinHeight() {
+ if (mAnimatingOut) return 0;
+ return Math.min(mLastHeight, mMinHeight);
+ }
+
+ @CalledByNative
+ private boolean onlyExpandControlsAtPageTop() {
+ return mOnlyExpandControlsAtPageTop;
+ }
+
+ @CalledByNative
private void didToggleFullscreenModeForTab(final boolean isFullscreen) {
// Delay hiding until after the animation. This comes from Chrome code.
if (mSystemUiFullscreenResizeRunnable != null) {
@@ -416,16 +580,16 @@ class BrowserControlsContainerView extends FrameLayout {
if (mIsFullscreen == isFullscreen) return;
mIsFullscreen = isFullscreen;
if (mIsFullscreen) {
+ mAnimatingOut = false;
hideControls();
- setFullscreenControlsOffset();
+ moveControlsOffScreen();
} else {
showControls();
setControlsOffset(0, mIsTop ? mLastHeight : 0);
}
}
- private void setFullscreenControlsOffset() {
- assert mIsFullscreen;
+ private void moveControlsOffScreen() {
setControlsOffset(mIsTop ? -mLastHeight : mLastHeight, 0);
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
index 66433bde80a..c814e8cd2cc 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
@@ -14,10 +14,14 @@ import android.view.View;
import android.view.ViewGroup;
import android.webkit.ValueCallback;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import org.chromium.base.ObserverList;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
+import org.chromium.components.embedder_support.view.ContentView;
import org.chromium.ui.base.DeviceFormFactor;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.weblayer_private.interfaces.APICallException;
@@ -36,7 +40,7 @@ import java.util.List;
* Implementation of {@link IBrowser}.
*/
@JNINamespace("weblayer")
-public class BrowserImpl extends IBrowser.Stub {
+public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChangeListener {
private final ObserverList<VisibleSecurityStateObserver> mVisibleSecurityStateObservers =
new ObserverList<VisibleSecurityStateObserver>();
@@ -56,6 +60,10 @@ public class BrowserImpl extends IBrowser.Stub {
private final ProfileImpl mProfile;
private Context mEmbedderActivityContext;
private BrowserViewController mViewController;
+ // Used to save UI state between destroyAttachmentState() and createAttachmentState() calls so
+ // it can be preserved during device rotations or other events that cause the Fragment to be
+ // recreated.
+ private BrowserViewController.State mViewControllerState;
private FragmentWindowAndroid mWindowAndroid;
private IBrowserClient mClient;
private LocaleChangedBroadcastReceiver mLocaleReceiver;
@@ -68,6 +76,7 @@ public class BrowserImpl extends IBrowser.Stub {
private Boolean mPasswordEchoEnabled;
private Boolean mDarkThemeEnabled;
private Float mFontScale;
+ private boolean mViewAttachedToWindow;
// Created in the constructor from saved state and used in setClient().
private PersistenceInfo mPersistenceInfo;
@@ -118,7 +127,7 @@ public class BrowserImpl extends IBrowser.Stub {
return mWindowAndroid;
}
- public ViewGroup getViewAndroidDelegateContainerView() {
+ public ContentView getViewAndroidDelegateContainerView() {
if (mViewController == null) return null;
return mViewController.getContentView();
}
@@ -135,7 +144,8 @@ public class BrowserImpl extends IBrowser.Stub {
assert mEmbedderActivityContext == null;
mWindowAndroid = windowAndroid;
mEmbedderActivityContext = embedderAppContext;
- mViewController = new BrowserViewController(windowAndroid);
+ mViewController = new BrowserViewController(
+ windowAndroid, this, mViewControllerState, mFragmentStoppedForConfigurationChange);
mLocaleReceiver = new LocaleChangedBroadcastReceiver(windowAndroid.getContext().get());
mPasswordEchoEnabled = null;
}
@@ -189,6 +199,20 @@ public class BrowserImpl extends IBrowser.Stub {
}
@Override
+ public void setTopViewAndScrollingBehavior(IObjectWrapper viewWrapper, int minHeight,
+ boolean onlyExpandControlsAtPageTop, boolean animate) {
+ StrictModeWorkaround.apply();
+ if (minHeight < 0) {
+ throw new IllegalArgumentException("Top view min height must be non-negative.");
+ }
+
+ getViewController().setTopControlsAnimationsEnabled(animate);
+ getViewController().setTopView(ObjectWrapper.unwrap(viewWrapper, View.class));
+ getViewController().setTopControlsMinHeight(minHeight);
+ getViewController().setOnlyExpandTopControlsAtPageTop(onlyExpandControlsAtPageTop);
+ }
+
+ @Override
public void setBottomView(IObjectWrapper viewWrapper) {
StrictModeWorkaround.apply();
getViewController().setBottomView(ObjectWrapper.unwrap(viewWrapper, View.class));
@@ -208,6 +232,8 @@ public class BrowserImpl extends IBrowser.Stub {
(ValueCallback<Boolean>) ObjectWrapper.unwrap(valueCallback, ValueCallback.class));
}
+ // Only call this if it's guaranteed that Browser is attached to an activity.
+ @NonNull
public BrowserViewController getViewController() {
if (mViewController == null) {
throw new RuntimeException("Currently Tab requires Activity context, so "
@@ -216,6 +242,12 @@ public class BrowserImpl extends IBrowser.Stub {
return mViewController;
}
+ // Can be null in the middle of destroy, or if fragment is detached from activity.
+ @Nullable
+ public BrowserViewController getPossiblyNullViewController() {
+ return mViewController;
+ }
+
public Context getContext() {
if (mWindowAndroid == null) {
return null;
@@ -368,7 +400,7 @@ public class BrowserImpl extends IBrowser.Stub {
return true;
}
- public TabImpl getActiveTab() {
+ public @Nullable TabImpl getActiveTab() {
return BrowserImplJni.get().getActiveTab(mNativeBrowser);
}
@@ -415,6 +447,7 @@ public class BrowserImpl extends IBrowser.Stub {
destroyTabImpl((TabImpl) iTab);
}
+ @CalledByNative
private void destroyTabImpl(TabImpl tab) {
tab.destroy();
}
@@ -459,9 +492,6 @@ public class BrowserImpl extends IBrowser.Stub {
public void onFragmentStop(boolean forConfigurationChange) {
mFragmentStoppedForConfigurationChange = forConfigurationChange;
mFragmentStarted = false;
- if (mFragmentStoppedForConfigurationChange) {
- destroyAttachmentState();
- }
updateAllTabs();
}
@@ -488,14 +518,41 @@ public class BrowserImpl extends IBrowser.Stub {
return mFragmentStoppedForConfigurationChange;
}
+ public boolean isViewAttachedToWindow() {
+ return mViewAttachedToWindow;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mViewAttachedToWindow = true;
+ updateAllTabsViewAttachedState();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ // Note this separate state is needed because v.isAttachedToWindow()
+ // still returns true inside this call.
+ mViewAttachedToWindow = false;
+ updateAllTabsViewAttachedState();
+ }
+
+ private void updateAllTabsViewAttachedState() {
+ for (Object tab : getTabs()) {
+ ((TabImpl) tab).updateViewAttachedStateFromBrowser();
+ }
+ }
+
private void destroyAttachmentState() {
if (mLocaleReceiver != null) {
mLocaleReceiver.destroy();
mLocaleReceiver = null;
}
if (mViewController != null) {
+ mViewControllerState = mViewController.getState();
mViewController.destroy();
mViewController = null;
+ mViewAttachedToWindow = false;
+ updateAllTabsViewAttachedState();
}
if (mWindowAndroid != null) {
mWindowAndroid.destroy();
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java
index 436113adde3..fd22fffcfb8 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java
@@ -15,10 +15,14 @@ import android.webkit.ValueCallback;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
+import androidx.annotation.Nullable;
+
import org.chromium.base.annotations.JNINamespace;
import org.chromium.components.browser_ui.modaldialog.AppModalPresenter;
+import org.chromium.components.browser_ui.widget.InsetObserverView;
import org.chromium.components.embedder_support.view.ContentView;
import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.BrowserControlsState;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
@@ -31,9 +35,21 @@ import org.chromium.ui.modelutil.PropertyModel;
*/
@JNINamespace("weblayer")
public final class BrowserViewController
- implements BrowserControlsContainerView.Listener,
+ implements BrowserControlsContainerView.Delegate,
WebContentsGestureStateTracker.OnGestureStateChangedListener,
ModalDialogManager.ModalDialogManagerObserver {
+ /** Information needed to restore the UI state after recreating the BrowserViewController. */
+ /* package */ static class State {
+ private BrowserControlsContainerView.State mTopControlsState;
+ private BrowserControlsContainerView.State mBottomControlsState;
+
+ private State(BrowserControlsContainerView.State topControlsState,
+ BrowserControlsContainerView.State bottomControlsState) {
+ mTopControlsState = topControlsState;
+ mBottomControlsState = bottomControlsState;
+ }
+ }
+
private final ContentViewRenderView mContentViewRenderView;
// Child of mContentViewRenderView. Be very careful adding Views to this, as any Views are not
// accessible (ContentView provides it's own accessible implementation that interacts with
@@ -53,12 +69,16 @@ public final class BrowserViewController
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
private final FragmentWindowAndroid mWindowAndroid;
+ private final View.OnAttachStateChangeListener mOnAttachedStateChangeListener;
private final ModalDialogManager mModalDialogManager;
private TabImpl mTab;
private WebContentsGestureStateTracker mGestureStateTracker;
+ @BrowserControlsState
+ private int mBrowserControlsConstraint = BrowserControlsState.BOTH;
+
/**
* The value of mCachedDoBrowserControlsShrinkRendererSize is set when
* WebContentsGestureStateTracker begins a gesture. This is necessary as the values should only
@@ -66,18 +86,24 @@ public final class BrowserViewController
*/
private boolean mCachedDoBrowserControlsShrinkRendererSize;
- public BrowserViewController(FragmentWindowAndroid windowAndroid) {
+ public BrowserViewController(FragmentWindowAndroid windowAndroid,
+ View.OnAttachStateChangeListener listener, @Nullable State savedState,
+ boolean recreateForConfigurationChange) {
mWindowAndroid = windowAndroid;
+ mOnAttachedStateChangeListener = listener;
Context context = mWindowAndroid.getContext().get();
- mContentViewRenderView = new ContentViewRenderView(context);
+ mContentViewRenderView = new ContentViewRenderView(context, recreateForConfigurationChange);
+ mContentViewRenderView.addOnAttachStateChangeListener(listener);
mContentViewRenderView.onNativeLibraryLoaded(
mWindowAndroid, ContentViewRenderView.MODE_SURFACE_VIEW);
mTopControlsContainerView =
- new BrowserControlsContainerView(context, mContentViewRenderView, this, true);
+ new BrowserControlsContainerView(context, mContentViewRenderView, this, true,
+ (savedState == null) ? null : savedState.mTopControlsState);
mTopControlsContainerView.setId(View.generateViewId());
mBottomControlsContainerView =
- new BrowserControlsContainerView(context, mContentViewRenderView, this, false);
+ new BrowserControlsContainerView(context, mContentViewRenderView, this, false,
+ (savedState == null) ? null : savedState.mBottomControlsState);
mBottomControlsContainerView.setId(View.generateViewId());
mContentView = ContentView.createContentView(
context, mTopControlsContainerView.getEventOffsetHandler(), null /* webContents */);
@@ -116,6 +142,7 @@ public final class BrowserViewController
public void destroy() {
mWindowAndroid.setModalDialogManager(null);
setActiveTab(null);
+ mContentViewRenderView.removeOnAttachStateChangeListener(mOnAttachedStateChangeListener);
mTopControlsContainerView.destroy();
mBottomControlsContainerView.destroy();
mContentViewRenderView.destroy();
@@ -126,12 +153,16 @@ public final class BrowserViewController
return mContentViewRenderView;
}
+ public InsetObserverView getInsetObserverView() {
+ return mContentViewRenderView.getInsetObserverView();
+ }
+
/** Returns the ViewGroup into which the InfoBarContainer should be parented. **/
public ViewGroup getInfoBarContainerParentView() {
return mContentViewRenderView;
}
- public ViewGroup getContentView() {
+ public ContentView getContentView() {
return mContentView;
}
@@ -156,6 +187,8 @@ public final class BrowserViewController
if (mTab != null) {
mTab.onDidLoseActive();
+ mTab.setBrowserControlsVisibilityConstraint(
+ ImplControlsVisibilityReason.ANIMATION, BrowserControlsState.BOTH);
// WebContentsGestureStateTracker is relatively cheap, easier to destroy rather than
// update WebContents.
mGestureStateTracker.destroy();
@@ -180,6 +213,8 @@ public final class BrowserViewController
mTopControlsContainerView.setWebContents(webContents);
mBottomControlsContainerView.setWebContents(webContents);
if (mTab != null) {
+ mTab.setBrowserControlsVisibilityConstraint(
+ ImplControlsVisibilityReason.ANIMATION, mBrowserControlsConstraint);
mTab.onDidGainActive(mTopControlsContainerView.getNativeHandle(),
mBottomControlsContainerView.getNativeHandle());
mContentView.requestFocus();
@@ -194,6 +229,18 @@ public final class BrowserViewController
mTopControlsContainerView.setView(view);
}
+ public void setTopControlsMinHeight(int minHeight) {
+ mTopControlsContainerView.setMinHeight(minHeight);
+ }
+
+ public void setOnlyExpandTopControlsAtPageTop(boolean onlyExpandControlsAtPageTop) {
+ mTopControlsContainerView.setOnlyExpandControlsAtPageTop(onlyExpandControlsAtPageTop);
+ }
+
+ public void setTopControlsAnimationsEnabled(boolean animationsEnabled) {
+ mTopControlsContainerView.setAnimationsEnabled(animationsEnabled);
+ }
+
public void setBottomView(View view) {
mBottomControlsContainerView.setView(view);
}
@@ -211,11 +258,19 @@ public final class BrowserViewController
}
@Override
- public void onBrowserControlsCompletelyShownOrHidden() {
+ public void refreshPageHeight() {
adjustWebContentsHeightIfNecessary();
}
@Override
+ public void setAnimationConstraint(@BrowserControlsState int constraint) {
+ mBrowserControlsConstraint = constraint;
+ if (mTab == null) return;
+ mTab.setBrowserControlsVisibilityConstraint(
+ ImplControlsVisibilityReason.ANIMATION, constraint);
+ }
+
+ @Override
public void onGestureStateChanged() {
// This is called from |mGestureStateTracker|.
assert mGestureStateTracker != null;
@@ -237,6 +292,11 @@ public final class BrowserViewController
onDialogVisibilityChanged(false);
}
+ /* package */ State getState() {
+ return new State(
+ mTopControlsContainerView.getState(), mBottomControlsContainerView.getState());
+ }
+
private void onDialogVisibilityChanged(boolean showing) {
if (WebLayerFactoryImpl.getClientMajorVersion() < 82) return;
@@ -256,8 +316,8 @@ public final class BrowserViewController
private void adjustWebContentsHeightIfNecessary() {
if (mGestureStateTracker == null || mGestureStateTracker.isInGestureOrScroll()
- || !mTopControlsContainerView.isCompletelyShownOrHidden()
- || !mBottomControlsContainerView.isCompletelyShownOrHidden()) {
+ || !mTopControlsContainerView.isCompletelyExpandedOrCollapsed()
+ || !mBottomControlsContainerView.isCompletelyExpandedOrCollapsed()) {
return;
}
mContentViewRenderView.setWebContentsHeightDelta(
@@ -289,6 +349,10 @@ public final class BrowserViewController
|| mBottomControlsContainerView.isControlVisible());
}
+ public boolean shouldAnimateBrowserControlsHeightChanges() {
+ return mTopControlsContainerView.shouldAnimateBrowserControlsHeightChanges();
+ }
+
/**
* Causes the browser controls to be fully shown. Take care in calling this. Normally the
* renderer drives the offsets, but this method circumvents that.
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ChildProcessServiceImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ChildProcessServiceImpl.java
index 599fd0dbc9d..71788e169fd 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ChildProcessServiceImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ChildProcessServiceImpl.java
@@ -25,12 +25,6 @@ import org.chromium.weblayer_private.interfaces.StrictModeWorkaround;
public final class ChildProcessServiceImpl extends IChildProcessService.Stub {
private ChildProcessService mService;
- // This should only be called in M80 or below.
- @UsedByReflection("WebLayer")
- public static IBinder create(Service service, Context appContext) {
- return create(service, appContext, WebLayerImpl.createRemoteContextV80(appContext));
- }
-
@UsedByReflection("WebLayer")
public static IBinder create(Service service, Context appContext, Context remoteContext) {
ClassLoaderContextWrapperFactory.setResourceOverrideContext(remoteContext);
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ConfirmInfoBar.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ConfirmInfoBar.java
deleted file mode 100644
index 4b49a4e8ebf..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ConfirmInfoBar.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.graphics.Bitmap;
-
-import androidx.annotation.ColorRes;
-
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.components.infobars.InfoBarLayout;
-
-/**
- * An infobar that presents the user with several buttons.
- *
- * TODO(newt): merge this into InfoBar.java.
- */
-public class ConfirmInfoBar extends InfoBar {
- /** Text shown on the primary button, e.g. "OK". */
- private final String mPrimaryButtonText;
-
- /** Text shown on the secondary button, e.g. "Cancel".*/
- private final String mSecondaryButtonText;
-
- /** Text shown on the link, e.g. "Learn more". */
- private final String mLinkText;
-
- protected ConfirmInfoBar(int iconDrawableId, @ColorRes int iconTintId, Bitmap iconBitmap,
- String message, String linkText, String primaryButtonText, String secondaryButtonText) {
- super(iconDrawableId, iconTintId, message, iconBitmap);
- mPrimaryButtonText = primaryButtonText;
- mSecondaryButtonText = secondaryButtonText;
- mLinkText = linkText;
- }
-
- @Override
- public void createContent(InfoBarLayout layout) {
- setButtons(layout, mPrimaryButtonText, mSecondaryButtonText);
- if (mLinkText != null && !mLinkText.isEmpty()) layout.appendMessageLinkText(mLinkText);
- }
-
- /**
- * If your custom infobar overrides this function, YOU'RE PROBABLY DOING SOMETHING WRONG.
- *
- * Adds buttons to the infobar. This should only be overridden in cases where an infobar
- * requires adding something other than a button for its secondary View on the bottom row
- * (almost never).
- *
- * @param primaryText Text to display on the primary button.
- * @param secondaryText Text to display on the secondary button. May be null.
- */
- protected void setButtons(InfoBarLayout layout, String primaryText, String secondaryText) {
- layout.setButtons(primaryText, secondaryText);
- }
-
- @Override
- public void onButtonClicked(final boolean isPrimaryButton) {
- int action = isPrimaryButton ? ActionType.OK : ActionType.CANCEL;
- onButtonClicked(action);
- }
-
- /**
- * Creates and begins the process for showing a ConfirmInfoBar.
- * @param iconId ID corresponding to the icon that will be shown for the infobar.
- * @param iconBitmap Bitmap to use if there is no equivalent Java resource for
- * iconId.
- * @param message Message to display to the user indicating what the infobar is for.
- * @param linkText Link text to display in addition to the message.
- * @param buttonOk String to display on the OK button.
- * @param buttonCancel String to display on the Cancel button.
- */
- @CalledByNative
- private static ConfirmInfoBar create(int iconId, Bitmap iconBitmap, String message,
- String linkText, String buttonOk, String buttonCancel) {
- ConfirmInfoBar infoBar = new ConfirmInfoBar(
- iconId, 0, iconBitmap, message, linkText, buttonOk, buttonCancel);
-
- return infoBar;
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java
index ac0235eaeb2..d5d471c5c57 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java
@@ -5,9 +5,13 @@
package org.chromium.weblayer_private;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.os.SystemClock;
+import android.util.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
@@ -25,9 +29,11 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.task.PostTask;
+import org.chromium.components.browser_ui.widget.InsetObserverView;
import org.chromium.content_public.browser.UiThreadTaskTraits;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.display.DisplayAndroid;
import org.chromium.ui.resources.ResourceManager;
import java.lang.annotation.Retention;
@@ -49,6 +55,8 @@ public class ContentViewRenderView extends RelativeLayout {
public static final int MODE_SURFACE_VIEW = 0;
public static final int MODE_TEXTURE_VIEW = 1;
+ private static final int CONFIG_TIMEOUT_MS = 1000;
+
// A child view of this class. Parent of SurfaceView/TextureView.
// Needed to support not resizing the surface when soft keyboard is showing.
private final SurfaceParent mSurfaceParent;
@@ -62,6 +70,9 @@ public class ContentViewRenderView extends RelativeLayout {
// The native side of this object.
private long mNativeContentViewRenderView;
+ // An invisible view that notifies observers of changes to window insets and safe area.
+ private InsetObserverView mInsetObserverView;
+
private WindowAndroid mWindowAndroid;
private WebContents mWebContents;
@@ -79,6 +90,13 @@ public class ContentViewRenderView extends RelativeLayout {
private boolean mCompositorHasSurface;
+ private DisplayAndroid.DisplayAndroidObserver mDisplayAndroidObserver;
+
+ // The time stamp when a configuration was detected (if any).
+ // This is used along with a timeout to determine if a resize surface resize
+ // is due to screen rotation.
+ private long mConfigurationChangedTimestamp;
+
// Common interface to listen to surface related events.
private interface SurfaceEventListener {
void surfaceCreated();
@@ -147,10 +165,7 @@ public class ContentViewRenderView extends RelativeLayout {
ContentViewRenderViewJni.get().surfaceChanged(mNativeContentViewRenderView,
canBeUsedWithSurfaceControl, format, width, height, surface);
mCompositorHasSurface = surface != null;
- if (mWebContents != null) {
- ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
- mNativeContentViewRenderView, mWebContents, width, height);
- }
+ maybeUpdatePhysicalBackingSize(width, height);
}
@Override
@@ -610,13 +625,30 @@ public class ContentViewRenderView extends RelativeLayout {
* hierarchy before the first draw to avoid a black flash that is seen every time a
* {@link SurfaceView} is added.
* @param context The context used to create this.
+ * @param recreateForConfigurationChange indicates that views are recreated after BrowserImpl
+ * is retained, but Activity is recreated, for a
+ * configuration change.
*/
- public ContentViewRenderView(Context context) {
+ public ContentViewRenderView(Context context, boolean recreateForConfigurationChange) {
super(context);
mSurfaceParent = new SurfaceParent(context);
addView(mSurfaceParent,
new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
- setBackgroundColor(Color.WHITE);
+
+ mInsetObserverView = InsetObserverView.create(context);
+ addView(mInsetObserverView);
+ mInsetObserverView.addObserver(new InsetObserverView.WindowInsetObserver() {
+ @Override
+ public void onInsetChanged(int left, int top, int right, int bottom) {
+ if (mWebContents != null && mWebContents.isFullscreenForCurrentTab()) {
+ updateWebContentsSize();
+ }
+ }
+
+ @Override
+ public void onSafeAreaChanged(Rect area) {}
+ });
+ if (recreateForConfigurationChange) updateConfigChangeTimeStamp();
}
/**
@@ -631,6 +663,14 @@ public class ContentViewRenderView extends RelativeLayout {
assert mNativeContentViewRenderView != 0;
mWindowAndroid = rootWindow;
requestMode(mode, (Boolean result) -> {});
+ mDisplayAndroidObserver = new DisplayAndroid.DisplayAndroidObserver() {
+ @Override
+ public void onRotationChanged(int rotation) {
+ updateConfigChangeTimeStamp();
+ }
+ };
+ mWindowAndroid.getDisplay().addObserver(mDisplayAndroidObserver);
+ updateBackgroundColor();
}
public void requestMode(@Mode int mode, ValueCallback<Boolean> callback) {
@@ -665,7 +705,21 @@ public class ContentViewRenderView extends RelativeLayout {
private void updateWebContentsSize() {
if (mWebContents == null) return;
- mWebContents.setSize(getWidth(), getHeight() - mWebContentsHeightDelta);
+ Size size = getViewportSize();
+ mWebContents.setSize(size.getWidth(), size.getHeight() - mWebContentsHeightDelta);
+ }
+
+ /** {@link CompositorViewHolder#getViewportSize()} for explanation. */
+ private Size getViewportSize() {
+ if (mWebContents.isFullscreenForCurrentTab()
+ && mWindowAndroid.getKeyboardDelegate().isKeyboardShowing(getContext(), this)) {
+ Rect visibleRect = new Rect();
+ getWindowVisibleDisplayFrame(visibleRect);
+ return new Size(Math.min(visibleRect.width(), getWidth()),
+ Math.min(visibleRect.height(), getHeight()));
+ }
+
+ return new Size(getWidth(), getHeight());
}
@Override
@@ -689,6 +743,12 @@ public class ContentViewRenderView extends RelativeLayout {
}
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ updateBackgroundColor();
+ }
+
/**
* Sets the background color of the surface / texture view. This method is necessary because
* the background color of ContentViewRenderView itself is covered by the background of
@@ -705,6 +765,11 @@ public class ContentViewRenderView extends RelativeLayout {
if (mCurrent != null) {
mCurrent.setBackgroundColor(color);
}
+ ContentViewRenderViewJni.get().updateBackgroundColor(mNativeContentViewRenderView);
+ }
+
+ public InsetObserverView getInsetObserverView() {
+ return mInsetObserverView;
}
/**
@@ -723,6 +788,10 @@ public class ContentViewRenderView extends RelativeLayout {
mRequested = null;
mCurrent = null;
+ if (mDisplayAndroidObserver != null) {
+ mWindowAndroid.getDisplay().removeObserver(mDisplayAndroidObserver);
+ mDisplayAndroidObserver = null;
+ }
mWindowAndroid = null;
while (!mPendingRunnables.isEmpty()) {
@@ -739,12 +808,9 @@ public class ContentViewRenderView extends RelativeLayout {
assert mNativeContentViewRenderView != 0;
mWebContents = webContents;
- if (webContents != null) {
- if (getWidth() != 0 && getHeight() != 0) {
- updateWebContentsSize();
- }
- ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
- mNativeContentViewRenderView, webContents, mPhysicalWidth, mPhysicalHeight);
+ if (webContents != null && getWidth() != 0 && getHeight() != 0) {
+ updateWebContentsSize();
+ maybeUpdatePhysicalBackingSize(mPhysicalWidth, mPhysicalHeight);
}
ContentViewRenderViewJni.get().setCurrentWebContents(
mNativeContentViewRenderView, webContents);
@@ -780,6 +846,18 @@ public class ContentViewRenderView extends RelativeLayout {
return mNativeContentViewRenderView;
}
+ private void updateBackgroundColor() {
+ int uiMode = getContext().getResources().getConfiguration().uiMode;
+ boolean darkThemeEnabled =
+ (uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+ setBackgroundColor(darkThemeEnabled ? Color.BLACK : Color.WHITE);
+ }
+
+ @CalledByNative
+ private int getBackgroundColor() {
+ return mBackgroundColor;
+ }
+
private boolean shouldAvoidSurfaceResizeForSoftKeyboard() {
// TextureView is more common with embedding use cases that should lead to resize.
boolean usingSurfaceView = mCurrent != null && mCurrent.getMode() == MODE_SURFACE_VIEW;
@@ -793,13 +871,25 @@ public class ContentViewRenderView extends RelativeLayout {
return inputMethodManager.isActive();
}
+ private void updateConfigChangeTimeStamp() {
+ mConfigurationChangedTimestamp = SystemClock.uptimeMillis();
+ }
+
+ private void maybeUpdatePhysicalBackingSize(int width, int height) {
+ if (mWebContents == null) return;
+ boolean forConfigChange =
+ SystemClock.uptimeMillis() - mConfigurationChangedTimestamp < CONFIG_TIMEOUT_MS;
+ ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
+ mNativeContentViewRenderView, mWebContents, width, height, forConfigChange);
+ }
+
@NativeMethods
interface Natives {
long init(ContentViewRenderView caller, WindowAndroid rootWindow);
void destroy(long nativeContentViewRenderView);
void setCurrentWebContents(long nativeContentViewRenderView, WebContents webContents);
- void onPhysicalBackingSizeChanged(
- long nativeContentViewRenderView, WebContents webContents, int width, int height);
+ void onPhysicalBackingSizeChanged(long nativeContentViewRenderView, WebContents webContents,
+ int width, int height, boolean forConfigChange);
void surfaceCreated(long nativeContentViewRenderView);
void surfaceDestroyed(long nativeContentViewRenderView, boolean cacheBackBuffer);
void surfaceChanged(long nativeContentViewRenderView, boolean canBeUsedWithSurfaceControl,
@@ -807,5 +897,6 @@ public class ContentViewRenderView extends RelativeLayout {
void setNeedsRedraw(long nativeContentViewRenderView);
void evictCachedSurface(long nativeContentViewRenderView);
ResourceManager getResourceManager(long nativeContentViewRenderView);
+ void updateBackgroundColor(long nativeContentViewRenderView);
}
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadCallbackProxy.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadCallbackProxy.java
index 8ff0107000e..defbe1e18dd 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadCallbackProxy.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadCallbackProxy.java
@@ -9,6 +9,7 @@ import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.webkit.ValueCallback;
+import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
@@ -64,7 +65,7 @@ public final class DownloadCallbackProxy {
String[] requestPermissions = new String[] {permission.WRITE_EXTERNAL_STORAGE};
window.requestPermissions(requestPermissions, (permissions, grantResults) -> {
- if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
+ if (grantResults.length == 0 || grantResults[0] == PackageManager.PERMISSION_DENIED) {
DownloadCallbackProxyJni.get().allowDownload(callbackId, false);
return;
}
@@ -91,6 +92,7 @@ public final class DownloadCallbackProxy {
ValueCallback<Boolean> callback = new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean result) {
+ ThreadUtils.assertOnUiThread();
if (mNativeDownloadCallbackProxy == 0) {
throw new IllegalStateException("Called after destroy()");
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadImpl.java
index b1046065bc3..cdb14ccbddf 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/DownloadImpl.java
@@ -347,7 +347,7 @@ public final class DownloadImpl extends IDownload.Stub {
? WebLayerNotificationChannels.ChannelId.COMPLETED_DOWNLOADS
: WebLayerNotificationChannels.ChannelId.ACTIVE_DOWNLOADS;
- WebLayerNotificationBuilder builder = WebLayerNotificationBuilder.create(
+ WebLayerNotificationWrapperBuilder builder = WebLayerNotificationWrapperBuilder.create(
channelId, new NotificationMetadata(0, NOTIFICATION_TAG, mNotificationId));
builder.setOngoing(true)
.setDeleteIntent(deletePendingIntent)
@@ -450,7 +450,7 @@ public final class DownloadImpl extends IDownload.Stub {
cancelPendingIntent, 0 /* no action for UMA */);
}
- notificationManager.notify(builder.buildChromeNotification());
+ notificationManager.notify(builder.buildNotificationWrapper());
}
/**
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ErrorPageCallbackProxy.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ErrorPageCallbackProxy.java
index 639a2003568..f1fd12a6753 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ErrorPageCallbackProxy.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ErrorPageCallbackProxy.java
@@ -43,6 +43,12 @@ public final class ErrorPageCallbackProxy {
return mClient.onBackToSafety();
}
+ @CalledByNative
+ private String getErrorPageContent(NavigationImpl navigation) throws RemoteException {
+ if (WebLayerFactoryImpl.getClientMajorVersion() < 86) return null;
+ return mClient.getErrorPageContent(navigation.getClientNavigation());
+ }
+
@NativeMethods
interface Natives {
long createErrorPageCallbackProxy(ErrorPageCallbackProxy proxy, long tab);
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java
index 253c35212d0..fdf5a8e3775 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java
@@ -4,22 +4,18 @@
package org.chromium.weblayer_private;
-import android.app.Activity;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import androidx.annotation.Nullable;
-import org.chromium.base.ContextUtils;
import org.chromium.base.PackageManagerUtils;
import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.components.external_intents.ExternalNavigationDelegate;
import org.chromium.components.external_intents.ExternalNavigationDelegate.StartActivityIfNeededResult;
-import org.chromium.components.external_intents.ExternalNavigationHandler;
import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult;
import org.chromium.components.external_intents.ExternalNavigationParams;
-import org.chromium.components.webapk.lib.client.ChromeWebApkHostSignature;
-import org.chromium.components.webapk.lib.client.WebApkValidator;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.WindowAndroid;
@@ -29,7 +25,6 @@ import org.chromium.url.Origin;
* WebLayer's implementation of the {@link ExternalNavigationDelegate}.
*/
public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegate {
- private static boolean sWebApkValidatorInitialized;
private final TabImpl mTab;
private boolean mTabDestroyed;
@@ -43,8 +38,8 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
}
@Override
- public Activity getActivityContext() {
- return ContextUtils.activityFromContext(mTab.getBrowser().getContext());
+ public Context getContext() {
+ return mTab.getBrowser().getContext();
}
@Override
@@ -92,14 +87,6 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
return StartActivityIfNeededResult.DID_NOT_HANDLE;
}
- @Override
- public boolean startIncognitoIntent(final Intent intent, final String referrerUrl,
- final String fallbackUrl, final boolean needsToCloseTab, final boolean proxy) {
- // TODO(crbug.com/1063399): Determine if this behavior should be refined.
- ExternalNavigationHandler.startActivity(intent, proxy, this);
- return true;
- }
-
// This method should never be invoked as WebLayer does not handle incoming intents.
@Override
public @OverrideUrlLoadingResult int handleIncognitoIntentTargetingSelf(
@@ -196,6 +183,11 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
}
@Override
+ public boolean canCloseTabOnIncognitoIntentLaunch() {
+ return hasValidTab();
+ }
+
+ @Override
public boolean isIntentForTrustedCallingApp(Intent intent) {
return false;
}
@@ -211,16 +203,6 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
}
@Override
- public boolean isValidWebApk(String packageName) {
- if (!sWebApkValidatorInitialized) {
- WebApkValidator.init(ChromeWebApkHostSignature.EXPECTED_SIGNATURE,
- ChromeWebApkHostSignature.PUBLIC_KEY);
- sWebApkValidatorInitialized = true;
- }
- return WebApkValidator.isValidWebApk(ContextUtils.getApplicationContext(), packageName);
- }
-
- @Override
public boolean handleWithAutofillAssistant(ExternalNavigationParams params, Intent targetIntent,
String browserFallbackUrl, boolean isGoogleReferrer) {
return false;
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/FaviconCallbackProxy.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FaviconCallbackProxy.java
new file mode 100644
index 00000000000..3c74a6dcd1b
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FaviconCallbackProxy.java
@@ -0,0 +1,64 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.weblayer_private;
+
+import android.graphics.Bitmap;
+import android.os.RemoteException;
+import android.util.AndroidRuntimeException;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
+import org.chromium.weblayer_private.interfaces.IFaviconFetcher;
+import org.chromium.weblayer_private.interfaces.IFaviconFetcherClient;
+
+/**
+ * Owns the c++ ErrorPageCallbackProxy class, which is responsible for forwarding all
+ * ErrorPageDelegate calls to this class, which in turn forwards to the
+ * ErrorPageCallbackClient.
+ */
+@JNINamespace("weblayer")
+public final class FaviconCallbackProxy extends IFaviconFetcher.Stub {
+ private TabImpl mTab;
+ private long mNativeFaviconCallbackProxy;
+ private IFaviconFetcherClient mClient;
+
+ FaviconCallbackProxy(TabImpl tab, long nativeTab, IFaviconFetcherClient client) {
+ assert client != null;
+ mTab = tab;
+ mClient = client;
+ mNativeFaviconCallbackProxy =
+ FaviconCallbackProxyJni.get().createFaviconCallbackProxy(this, nativeTab);
+ }
+
+ @Override
+ public void destroy() {
+ // As Tab implicitly destroys this, and the embedder is allowed to destroy this, allow
+ // destroy() to be called multiple times.
+ if (mNativeFaviconCallbackProxy == 0) {
+ return;
+ }
+ mTab.removeFaviconCallbackProxy(this);
+ try {
+ mClient.onDestroyed();
+ } catch (RemoteException e) {
+ throw new AndroidRuntimeException(e);
+ }
+ FaviconCallbackProxyJni.get().deleteFaviconCallbackProxy(mNativeFaviconCallbackProxy);
+ mNativeFaviconCallbackProxy = 0;
+ mClient = null;
+ }
+
+ @CalledByNative
+ private void onFaviconChanged(Bitmap bitmap) throws RemoteException {
+ mClient.onFaviconChanged(bitmap);
+ }
+
+ @NativeMethods
+ interface Natives {
+ long createFaviconCallbackProxy(FaviconCallbackProxy proxy, long tab);
+ void deleteFaviconCallbackProxy(long proxy);
+ }
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/FullscreenCallbackProxy.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FullscreenCallbackProxy.java
index 5a631624551..88fe5da222d 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/FullscreenCallbackProxy.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FullscreenCallbackProxy.java
@@ -7,6 +7,9 @@ package org.chromium.weblayer_private;
import android.os.RemoteException;
import android.webkit.ValueCallback;
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
@@ -22,12 +25,15 @@ import org.chromium.weblayer_private.interfaces.ObjectWrapper;
public final class FullscreenCallbackProxy {
private long mNativeFullscreenCallbackProxy;
private IFullscreenCallbackClient mClient;
+ private TabImpl mTab;
+ private FullscreenToast mToast;
- FullscreenCallbackProxy(long tab, IFullscreenCallbackClient client) {
+ FullscreenCallbackProxy(TabImpl tab, long nativeTab, IFullscreenCallbackClient client) {
assert client != null;
mClient = client;
+ mTab = tab;
mNativeFullscreenCallbackProxy =
- FullscreenCallbackProxyJni.get().createFullscreenCallbackProxy(this, tab);
+ FullscreenCallbackProxyJni.get().createFullscreenCallbackProxy(this, nativeTab);
}
public void setClient(IFullscreenCallbackClient client) {
@@ -39,6 +45,19 @@ public final class FullscreenCallbackProxy {
FullscreenCallbackProxyJni.get().deleteFullscreenCallbackProxy(
mNativeFullscreenCallbackProxy);
mNativeFullscreenCallbackProxy = 0;
+ destroyToast();
+ mTab = null;
+ }
+
+ public void destroyToast() {
+ if (mToast == null) return;
+ mToast.destroy();
+ mToast = null;
+ }
+
+ @VisibleForTesting
+ public boolean didShowFullscreenToast() {
+ return mToast != null && mToast.didShowFullscreenToast();
}
@CalledByNative
@@ -46,18 +65,23 @@ public final class FullscreenCallbackProxy {
ValueCallback<Void> exitFullscreenCallback = new ValueCallback<Void>() {
@Override
public void onReceiveValue(Void result) {
+ ThreadUtils.assertOnUiThread();
if (mNativeFullscreenCallbackProxy == 0) {
throw new IllegalStateException("Called after destroy()");
}
+ destroyToast();
FullscreenCallbackProxyJni.get().doExitFullscreen(mNativeFullscreenCallbackProxy);
}
};
+ destroyToast();
+ mToast = new FullscreenToast(mTab);
mClient.enterFullscreen(ObjectWrapper.wrap(exitFullscreenCallback));
}
@CalledByNative
private void exitFullscreen() throws RemoteException {
mClient.exitFullscreen();
+ destroyToast();
}
@NativeMethods
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/FullscreenToast.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FullscreenToast.java
new file mode 100644
index 00000000000..1133555a7a6
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FullscreenToast.java
@@ -0,0 +1,103 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.weblayer_private;
+
+import android.view.Gravity;
+import android.view.View;
+
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.components.embedder_support.view.ContentView;
+import org.chromium.ui.widget.Toast;
+
+/**
+ * FullscreenToast is responsible for showing toast when fullscreen mode is entered. As the embedder
+ * is responsible for entering fullscreen mode, there is no guarantee when or if fullscreen mode
+ * will be entered. This waits for the system to enter fullscreen mode and then show the toast. If
+ * fullscreen isn't entered after a short delay this assumes the embedder won't enter fullscreen
+ * and the toast is never shown.
+ */
+public final class FullscreenToast {
+ // The tab the toast is showing from.
+ private TabImpl mTab;
+
+ // View used to register for system ui change notification.
+ private ContentView mView;
+
+ private View.OnSystemUiVisibilityChangeListener mSystemUiVisibilityChangeListener;
+
+ // Set to true once toast is shown.
+ private boolean mDidShowToast;
+
+ // The toast.
+ private Toast mToast;
+
+ FullscreenToast(TabImpl tab) {
+ mTab = tab;
+ // TODO(https://crbug.com/1130096): This should really be handled lower down in the stack.
+ if (tab.getBrowser().getActiveTab() != tab) return;
+ addSystemUiChangedObserver();
+ }
+
+ @VisibleForTesting
+ public boolean didShowFullscreenToast() {
+ return mDidShowToast;
+ }
+
+ public void destroy() {
+ // This may be called more than once.
+ if (mTab == null) return;
+
+ if (mSystemUiVisibilityChangeListener != null) {
+ // mSystemUiVisibilityChangeListener is only installed if mView is non-null.
+ assert mView != null;
+ mView.removeOnSystemUiVisibilityChangeListener(mSystemUiVisibilityChangeListener);
+ mSystemUiVisibilityChangeListener = null;
+ }
+ mTab = null;
+ mView = null;
+ if (mToast != null) {
+ mToast.cancel();
+ mToast = null;
+ }
+ }
+
+ private void addSystemUiChangedObserver() {
+ if (mTab.getBrowser().getViewAndroidDelegateContainerView() == null) {
+ return;
+ }
+ mView = mTab.getBrowser().getViewAndroidDelegateContainerView();
+ mSystemUiVisibilityChangeListener = new View.OnSystemUiVisibilityChangeListener() {
+ @Override
+ public void onSystemUiVisibilityChange(int visibility) {
+ // The listener should have been removed if destroy() was called.
+ assert mTab != null;
+ if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
+ // No longer in fullscreen. Destroy.
+ destroy();
+ } else if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+ && !mDidShowToast) {
+ // Only show the toast when navigation is hidden and toast wasn't already shown.
+ showToast();
+ mDidShowToast = true;
+ }
+ }
+ };
+ mView.addOnSystemUiVisibilityChangeListener(mSystemUiVisibilityChangeListener);
+ // See class description for details on why a timeout is used.
+ mView.postDelayed(() -> {
+ if (!mDidShowToast) destroy();
+ }, 1000);
+ }
+
+ private void showToast() {
+ assert mToast == null;
+ mDidShowToast = true;
+ int resId = R.string.immersive_fullscreen_api_notification;
+ mToast = Toast.makeText(mView.getContext(), resId, Toast.LENGTH_LONG);
+ mToast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 0);
+ mToast.show();
+ }
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/GoogleAccountsCallbackProxy.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/GoogleAccountsCallbackProxy.java
new file mode 100644
index 00000000000..25b12a730bf
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/GoogleAccountsCallbackProxy.java
@@ -0,0 +1,77 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.weblayer_private;
+
+import android.os.RemoteException;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
+import org.chromium.components.signin.GAIAServiceType;
+import org.chromium.weblayer_private.interfaces.GoogleAccountServiceType;
+import org.chromium.weblayer_private.interfaces.IGoogleAccountsCallbackClient;
+
+/**
+ * Owns the C++ GoogleAccountsCallbackProxy which is responsible for forwarding all calls to this
+ * class.
+ */
+@JNINamespace("weblayer")
+public final class GoogleAccountsCallbackProxy {
+ private long mNativeGoogleAccountsCallbackProxy;
+ private IGoogleAccountsCallbackClient mClient;
+
+ GoogleAccountsCallbackProxy(long tab, IGoogleAccountsCallbackClient client) {
+ assert client != null;
+ mClient = client;
+ mNativeGoogleAccountsCallbackProxy =
+ GoogleAccountsCallbackProxyJni.get().createGoogleAccountsCallbackProxy(this, tab);
+ }
+
+ public void setClient(IGoogleAccountsCallbackClient client) {
+ assert client != null;
+ mClient = client;
+ }
+
+ public void destroy() {
+ GoogleAccountsCallbackProxyJni.get().deleteGoogleAccountsCallbackProxy(
+ mNativeGoogleAccountsCallbackProxy);
+ mNativeGoogleAccountsCallbackProxy = 0;
+ }
+
+ @CalledByNative
+ private void onGoogleAccountsRequest(@GAIAServiceType int serviceType, String email,
+ String continueUrl, boolean isSameTab) throws RemoteException {
+ mClient.onGoogleAccountsRequest(
+ implTypeToJavaType(serviceType), email, continueUrl, isSameTab);
+ }
+
+ @CalledByNative
+ private String getGaiaId() throws RemoteException {
+ return mClient.getGaiaId();
+ }
+
+ @GoogleAccountServiceType
+ private static int implTypeToJavaType(@GAIAServiceType int type) {
+ switch (type) {
+ case GAIAServiceType.GAIA_SERVICE_TYPE_SIGNOUT:
+ return GoogleAccountServiceType.SIGNOUT;
+ case GAIAServiceType.GAIA_SERVICE_TYPE_ADDSESSION:
+ return GoogleAccountServiceType.ADD_SESSION;
+ // SIGNUP and INCOGNITO should not be possible currently, so pass through to DEFAULT.
+ case GAIAServiceType.GAIA_SERVICE_TYPE_SIGNUP:
+ case GAIAServiceType.GAIA_SERVICE_TYPE_INCOGNITO:
+ case GAIAServiceType.GAIA_SERVICE_TYPE_DEFAULT:
+ return GoogleAccountServiceType.DEFAULT;
+ }
+ assert false;
+ return GoogleAccountServiceType.DEFAULT;
+ }
+
+ @NativeMethods
+ interface Natives {
+ long createGoogleAccountsCallbackProxy(GoogleAccountsCallbackProxy proxy, long tab);
+ void deleteGoogleAccountsCallbackProxy(long proxy);
+ }
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBar.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBar.java
deleted file mode 100644
index 69e4754d98b..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBar.java
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.annotation.ColorRes;
-import androidx.annotation.Nullable;
-
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-import org.chromium.base.annotations.NativeMethods;
-import org.chromium.chrome.browser.infobar.InfoBarIdentifier;
-import org.chromium.components.infobars.InfoBarInteractionHandler;
-import org.chromium.components.infobars.InfoBarLayout;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * The base class for all InfoBar classes.
- * Note that infobars expire by default when a new navigation occurs.
- * Make sure to use setExpireOnNavigation(false) if you want an infobar to be sticky.
- */
-@JNINamespace("weblayer")
-public abstract class InfoBar implements InfoBarInteractionHandler, InfoBarUiItem {
- private static final String TAG = "InfoBar";
-
- /**
- * Interface for InfoBar to interact with its container.
- */
- public interface Container {
- /**
- * @return True if the infobar is in front.
- */
- boolean isFrontInfoBar(InfoBar infoBar);
-
- /**
- * Remove the infobar from its container.
- * @param infoBar InfoBar to remove from the View hierarchy.
- */
- void removeInfoBar(InfoBar infoBar);
-
- /**
- * Notifies that an infobar's View ({@link InfoBar#getView}) has changed.
- */
- void notifyInfoBarViewChanged();
-
- /**
- * @return True if the container's destroy() method has been called.
- */
- boolean isDestroyed();
- }
-
- private final int mIconDrawableId;
- private final Bitmap mIconBitmap;
- private final @ColorRes int mIconTintId;
- private final CharSequence mMessage;
-
- private @Nullable Container mContainer;
- private @Nullable View mView;
- private @Nullable Context mContext;
-
- private boolean mIsDismissed;
- private boolean mControlsEnabled = true;
-
- private @Nullable PropertyModel mModel;
-
- // This points to the InfoBarAndroid class not any of its subclasses.
- private long mNativeInfoBarPtr;
-
- /**
- * Constructor for regular infobars.
- * @param iconDrawableId ID of the resource to use for the Icon. If 0, no icon will be shown.
- * @param iconTintId The {@link ColorRes} used as tint for the {@code iconDrawableId}.
- * @param message The message to show in the infobar.
- * @param iconBitmap Icon to draw, in bitmap form. Used mainly for generated icons.
- */
- public InfoBar(
- int iconDrawableId, @ColorRes int iconTintId, CharSequence message, Bitmap iconBitmap) {
- mIconDrawableId = iconDrawableId;
- mIconBitmap = iconBitmap;
- mIconTintId = iconTintId;
- mMessage = message;
- }
-
- /**
- * Stores a pointer to the native-side counterpart of this InfoBar.
- * @param nativeInfoBarPtr Pointer to the native InfoBarAndroid, not to its subclass.
- */
- @CalledByNative
- private final void setNativeInfoBar(long nativeInfoBarPtr) {
- mNativeInfoBarPtr = nativeInfoBarPtr;
- }
-
- @CalledByNative
- protected void onNativeDestroyed() {
- mNativeInfoBarPtr = 0;
- }
-
- /**
- * Sets the Context used when creating the InfoBar.
- */
- public void setContext(Context context) {
- mContext = context;
- }
-
- /**
- * @return The {@link Context} used to create the InfoBar. This will be null before the InfoBar
- * is added to an {@link InfoBarContainer}, or after the InfoBar is closed.
- */
- @Nullable
- protected Context getContext() {
- return mContext;
- }
-
- /**
- * Creates the View that represents the InfoBar.
- * @return The View representing the InfoBar.
- */
- public final View createView() {
- assert mContext != null;
-
- if (usesCompactLayout()) {
- InfoBarCompactLayout layout = new InfoBarCompactLayout(
- mContext, this, mIconDrawableId, mIconTintId, mIconBitmap);
- createCompactLayoutContent(layout);
- mView = layout;
- } else {
- InfoBarLayout layout = new InfoBarLayout(
- mContext, this, mIconDrawableId, mIconTintId, mIconBitmap, mMessage);
- createContent(layout);
- layout.onContentCreated();
- mView = layout;
- }
-
- return mView;
- }
-
- /**
- * @return The model for this infobar if one was created.
- */
- @Nullable
- PropertyModel getModel() {
- return mModel;
- }
-
- /**
- * If this returns true, the infobar contents will be replaced with a one-line layout.
- * When overriding this, also override {@link #getAccessibilityMessage}.
- */
- protected boolean usesCompactLayout() {
- return false;
- }
-
- /**
- * Prepares the InfoBar for display and adds InfoBar-specific controls to the layout.
- * @param layout Layout containing all of the controls.
- */
- protected void createContent(InfoBarLayout layout) {}
-
- /**
- * Prepares and inserts views into an {@link InfoBarCompactLayout}.
- * {@link #usesCompactLayout} must return 'true' for this function to be called.
- * @param layout Layout to plug views into.
- */
- protected void createCompactLayoutContent(InfoBarCompactLayout layout) {}
-
- /**
- * Replaces the View currently shown in the infobar with the given View. Triggers the swap
- * animation via the InfoBarContainer.
- */
- protected void replaceView(View newView) {
- mView = newView;
- mContainer.notifyInfoBarViewChanged();
- }
-
- /**
- * Returns the View shown in this infobar. Only valid after createView() has been called.
- */
- @Override
- public View getView() {
- return mView;
- }
-
- /**
- * Returns the accessibility message to announce when this infobar is first shown.
- * Override this if the InfoBar doesn't have {@link R.id.infobar_message}. It is usually the
- * case when it is in CompactLayout.
- */
- protected CharSequence getAccessibilityMessage(CharSequence defaultTitle) {
- return defaultTitle == null ? "" : defaultTitle;
- }
-
- @Override
- public CharSequence getAccessibilityText() {
- if (mView == null) return "";
-
- CharSequence title = null;
- TextView messageView = (TextView) mView.findViewById(R.id.infobar_message);
- if (messageView != null) {
- title = messageView.getText();
- }
- title = getAccessibilityMessage(title);
- if (title.length() > 0) {
- title = title + " ";
- }
- // TODO(crbug/773717): Avoid string concatenation due to i18n.
- return title + mContext.getString(R.string.weblayer_bottom_bar_screen_position);
- }
-
- @Override
- public int getPriority() {
- return InfoBarPriority.PAGE_TRIGGERED;
- }
-
- @Override
- @InfoBarIdentifier
- public int getInfoBarIdentifier() {
- if (mNativeInfoBarPtr == 0) return InfoBarIdentifier.INVALID;
- return InfoBarJni.get().getInfoBarIdentifier(mNativeInfoBarPtr, InfoBar.this);
- }
-
- /**
- * @return whether the infobar actually needed closing.
- */
- @CalledByNative
- private boolean closeInfoBar() {
- if (!mIsDismissed) {
- mIsDismissed = true;
- if (!mContainer.isDestroyed()) {
- // If the container was destroyed, it's already been emptied of all its infobars.
- onStartedHiding();
- mContainer.removeInfoBar(this);
- }
- mContainer = null;
- mView = null;
- mContext = null;
- return true;
- }
- return false;
- }
-
- /**
- * @return If the infobar is the front infobar (i.e. visible and not hidden behind other
- * infobars).
- */
- public boolean isFrontInfoBar() {
- return mContainer.isFrontInfoBar(this);
- }
-
- /**
- * Called just before the Java infobar has begun hiding. Give the chance to clean up any child
- * UI that may remain open.
- */
- protected void onStartedHiding() {}
-
- /**
- * Returns pointer to native InfoBarAndroid instance.
- * TODO(crbug/1056346): The function is used in subclasses typically to get Tab reference. When
- * Tab is modularized, replace this function with the one that returns Tab reference.
- */
- protected long getNativeInfoBarPtr() {
- return mNativeInfoBarPtr;
- }
-
- /**
- * Sets the Container that displays the InfoBar.
- */
- public void setContainer(Container container) {
- mContainer = container;
- }
-
- /**
- * @return Whether or not this InfoBar is already dismissed (i.e. closed).
- */
- protected boolean isDismissed() {
- return mIsDismissed;
- }
-
- @Override
- public boolean areControlsEnabled() {
- return mControlsEnabled;
- }
-
- @Override
- public void setControlsEnabled(boolean state) {
- mControlsEnabled = state;
- }
-
- @Override
- public void onClick() {
- setControlsEnabled(false);
- }
-
- @Override
- public void onButtonClicked(boolean isPrimaryButton) {}
-
- @Override
- public void onLinkClicked() {
- if (mNativeInfoBarPtr != 0) InfoBarJni.get().onLinkClicked(mNativeInfoBarPtr, InfoBar.this);
- }
-
- /**
- * Performs some action related to the button being clicked.
- * @param action The type of action defined in {@link ActionType} in this class.
- */
- protected void onButtonClicked(@ActionType int action) {
- if (mNativeInfoBarPtr != 0) {
- InfoBarJni.get().onButtonClicked(mNativeInfoBarPtr, InfoBar.this, action);
- }
- }
-
- @Override
- public void onCloseButtonClicked() {
- if (mNativeInfoBarPtr != 0 && !mIsDismissed) {
- InfoBarJni.get().onCloseButtonClicked(mNativeInfoBarPtr, InfoBar.this);
- }
- }
-
- @NativeMethods
- interface Natives {
- int getInfoBarIdentifier(long nativeInfoBarAndroid, InfoBar caller);
- void onLinkClicked(long nativeInfoBarAndroid, InfoBar caller);
- void onButtonClicked(long nativeInfoBarAndroid, InfoBar caller, int action);
- void onCloseButtonClicked(long nativeInfoBarAndroid, InfoBar caller);
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarCompactLayout.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarCompactLayout.java
deleted file mode 100644
index c2303eaea6b..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarCompactLayout.java
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.method.LinkMovementMethod;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.ColorRes;
-import androidx.annotation.StringRes;
-import androidx.appcompat.content.res.AppCompatResources;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.Callback;
-import org.chromium.components.infobars.InfoBarInteractionHandler;
-import org.chromium.components.infobars.InfoBarLayout;
-import org.chromium.components.infobars.InfoBarMessageView;
-import org.chromium.ui.text.NoUnderlineClickableSpan;
-import org.chromium.ui.widget.ChromeImageButton;
-
-/**
- * Lays out controls along a line, sandwiched between an (optional) icon and close button.
- * This should only be used by the {@link InfoBar} class, and is created when the InfoBar subclass
- * declares itself to be using a compact layout via {@link InfoBar#usesCompactLayout}.
- */
-public class InfoBarCompactLayout extends LinearLayout implements View.OnClickListener {
- private final InfoBarInteractionHandler mInfoBar;
- private final int mCompactInfoBarSize;
- private final int mIconWidth;
- private final View mCloseButton;
-
- /**
- * Constructs a compat layout for the specified infobar.
- * @param context The context used to render.
- * @param infoBar {@link InfoBarInteractionHandler} that listens to events.
- * @param iconResourceId Resource ID of the icon to use for the infobar.
- * @param iconTintId The {@link ColorRes} used as tint for {@code iconResourceId}.
- * @param iconBitmap Bitmap for the icon to use, if {@code iconResourceId} is not set.
- */
- // TODO(crbug/1056346): ctor is made public to allow access from InfoBar. Once
- // InfoBar is modularized, restore access to package private.
- public InfoBarCompactLayout(Context context, InfoBarInteractionHandler infoBar,
- int iconResourceId, @ColorRes int iconTintId, Bitmap iconBitmap) {
- super(context);
- mInfoBar = infoBar;
- mCompactInfoBarSize =
- context.getResources().getDimensionPixelOffset(R.dimen.infobar_compact_size);
- mIconWidth = context.getResources().getDimensionPixelOffset(R.dimen.infobar_big_icon_size);
-
- setOrientation(LinearLayout.HORIZONTAL);
- setGravity(Gravity.CENTER_VERTICAL);
-
- prepareIcon(iconResourceId, iconTintId, iconBitmap);
- mCloseButton = prepareCloseButton();
- }
-
- @Override
- public void onClick(View view) {
- if (view.getId() == R.id.infobar_close_button) {
- mInfoBar.onCloseButtonClicked();
- } else {
- assert false;
- }
- }
-
- /**
- * Inserts a view before the close button.
- * @param view View to insert.
- * @param weight Weight to assign to it.
- */
- // TODO(crbug/1056346): addContent is made public to allow access from InfoBar. Once
- // InfoBar is modularized, restore access to protected.
- public void addContent(View view, float weight) {
- LinearLayout.LayoutParams params;
- if (weight <= 0.0f) {
- params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, mCompactInfoBarSize);
- } else {
- params = new LinearLayout.LayoutParams(0, LayoutParams.WRAP_CONTENT, weight);
- }
- view.setMinimumHeight(mCompactInfoBarSize);
- params.gravity = Gravity.BOTTOM;
- addView(view, indexOfChild(mCloseButton), params);
- }
-
- /**
- * Adds an icon to the start of the infobar, if the infobar requires one.
- * @param iconResourceId Resource ID of the icon to use.
- * @param iconTintId The {@link ColorRes} used as tint for {@code iconResourceId}.
- * @param iconBitmap Raw {@link Bitmap} to use instead of a resource.
- */
- private void prepareIcon(int iconResourceId, @ColorRes int iconTintId, Bitmap iconBitmap) {
- ImageView iconView =
- InfoBarLayout.createIconView(getContext(), iconResourceId, iconTintId, iconBitmap);
- if (iconView != null) {
- LinearLayout.LayoutParams iconParams =
- new LinearLayout.LayoutParams(mIconWidth, mCompactInfoBarSize);
- addView(iconView, iconParams);
- }
- }
-
- /**
- * Creates a close button that can be inserted into an infobar.
- * NOTE: This was forked from //chrome's InfoBarLayout.java, as WebLayer supports only compact
- * infobars and does not have a corresponding InfoBarLayout.java.
- * @param context Context to grab resources from.
- * @return {@link ImageButton} that represents a close button.
- */
- static ImageButton createCloseButton(Context context) {
- final ColorStateList tint =
- AppCompatResources.getColorStateList(context, R.color.default_icon_color);
- TypedArray a =
- context.obtainStyledAttributes(new int[] {android.R.attr.selectableItemBackground});
- Drawable closeButtonBackground = a.getDrawable(0);
- a.recycle();
-
- ChromeImageButton closeButton = new ChromeImageButton(context);
- closeButton.setId(R.id.infobar_close_button);
- closeButton.setImageResource(R.drawable.btn_close);
- ApiCompatibilityUtils.setImageTintList(closeButton, tint);
- closeButton.setBackground(closeButtonBackground);
- closeButton.setContentDescription(context.getString(R.string.weblayer_infobar_close));
- closeButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
- return closeButton;
- }
-
- /** Adds a close button to the end of the infobar. */
- private View prepareCloseButton() {
- ImageButton closeButton = createCloseButton(getContext());
- closeButton.setOnClickListener(this);
- LinearLayout.LayoutParams closeParams =
- new LinearLayout.LayoutParams(mCompactInfoBarSize, mCompactInfoBarSize);
- addView(closeButton, closeParams);
- return closeButton;
- }
-
- /**
- * Helps building a standard message to display in a compact InfoBar. The message can feature
- * a link to perform and action from this infobar.
- */
- public static class MessageBuilder {
- private final InfoBarCompactLayout mLayout;
- private CharSequence mMessage;
- private CharSequence mLink;
-
- /** @param layout The layout we are building a message view for. */
- public MessageBuilder(InfoBarCompactLayout layout) {
- mLayout = layout;
- }
-
- public MessageBuilder withText(CharSequence message) {
- assert mMessage == null;
- mMessage = message;
-
- return this;
- }
-
- public MessageBuilder withText(@StringRes int messageResId) {
- assert mMessage == null;
- mMessage = mLayout.getResources().getString(messageResId);
-
- return this;
- }
-
- /** Appends a link after the main message, its displayed text being the specified string. */
- public MessageBuilder withLink(CharSequence label, Callback<View> onTapCallback) {
- assert mLink == null;
-
- final Resources resources = mLayout.getResources();
- SpannableString link = new SpannableString(label);
- link.setSpan(new NoUnderlineClickableSpan(resources, onTapCallback), 0, label.length(),
- Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
- mLink = link;
-
- return this;
- }
-
- /**
- * Appends a link after the main message, its displayed text being constructed from the
- * given resource ID.
- */
- public MessageBuilder withLink(@StringRes int textResId, Callback<View> onTapCallback) {
- final Resources resources = mLayout.getResources();
- String label = resources.getString(textResId);
- return withLink(label, onTapCallback);
- }
-
- /** Finalizes the message view as set up in the builder and inserts it into the layout. */
- public void buildAndInsert() {
- mLayout.addContent(build(), 1f);
- }
-
- /**
- * Finalizes the message view as set up in the builder. The caller is responsible for adding
- * it to the parent layout.
- */
- public View build() {
- // TODO(dgn): Should be able to handle ReaderMode and Survey infobars but they have non
- // standard interaction models (no button/link, whole bar is a button) or style (large
- // rather than default text). Revisit after snowflake review.
-
- assert mMessage != null;
-
- final int messagePadding = mLayout.getResources().getDimensionPixelOffset(
- R.dimen.infobar_compact_message_vertical_padding);
-
- SpannableStringBuilder builder = new SpannableStringBuilder();
- builder.append(mMessage);
- if (mLink != null) builder.append(" ").append(mLink);
-
- TextView prompt = new InfoBarMessageView(mLayout.getContext());
- ApiCompatibilityUtils.setTextAppearance(
- prompt, R.style.TextAppearance_TextMedium_Primary);
- prompt.setText(builder);
- prompt.setGravity(Gravity.CENTER_VERTICAL);
- prompt.setPadding(0, messagePadding, 0, messagePadding);
-
- if (mLink != null) prompt.setMovementMethod(LinkMovementMethod.getInstance());
-
- return prompt;
- }
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainer.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainer.java
index 15037971602..f0be246a46d 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainer.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainer.java
@@ -16,6 +16,9 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.chrome.browser.infobar.InfoBarIdentifier;
+import org.chromium.components.infobars.InfoBar;
+import org.chromium.components.infobars.InfoBarAnimationListener;
+import org.chromium.components.infobars.InfoBarUiItem;
import org.chromium.content_public.browser.NavigationHandle;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.WebContentsObserver;
@@ -49,26 +52,6 @@ public class InfoBarContainer implements KeyboardVisibilityListener, InfoBar.Con
}
/**
- * A listener for the InfoBar animations.
- */
- public interface InfoBarAnimationListener {
- public static final int ANIMATION_TYPE_SHOW = 0;
- public static final int ANIMATION_TYPE_SWAP = 1;
- public static final int ANIMATION_TYPE_HIDE = 2;
-
- /**
- * Notifies the subscriber when an animation is completed.
- */
- void notifyAnimationFinished(int animationType);
-
- /**
- * Notifies the subscriber when all animations are finished.
- * @param frontInfoBar The frontmost infobar or {@code null} if none are showing.
- */
- void notifyAllAnimationsFinished(InfoBarUiItem frontInfoBar);
- }
-
- /**
* An observer that is notified of changes to a {@link InfoBarContainer} object.
*/
public interface InfoBarContainerObserver {
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerLayout.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerLayout.java
deleted file mode 100644
index 4f91d6f437d..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerLayout.java
+++ /dev/null
@@ -1,852 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.Resources;
-import android.text.TextUtils;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import org.chromium.ui.widget.OptimizedFrameLayout;
-import org.chromium.weblayer_private.InfoBarContainer.InfoBarAnimationListener;
-
-import java.util.ArrayList;
-
-/**
- * Layout that displays infobars in a stack. Handles all the animations when adding or removing
- * infobars and when swapping infobar contents.
- *
- * The first infobar to be added is visible at the front of the stack. Later infobars peek up just
- * enough behind the front infobar to signal their existence; their contents aren't visible at all.
- * The stack has a max depth of three infobars. If additional infobars are added beyond this, they
- * won't be visible at all until infobars in front of them are dismissed.
- *
- * Animation details:
- * - Newly added infobars slide up from the bottom and then their contents fade in.
- * - Disappearing infobars slide down and away. The remaining infobars, if any, resize to the
- * new front infobar's size, then the content of the new front infobar fades in.
- * - When swapping the front infobar's content, the old content fades out, the infobar resizes to
- * the new content's size, then the new content fades in.
- * - Only a single animation happens at a time. If several infobars are added and/or removed in
- * quick succession, the animations will be queued and run sequentially.
- *
- * Note: this class depends only on Android view code; it intentionally does not depend on any other
- * infobar code. This is an explicit design decision and should remain this way.
- *
- * TODO(newt): what happens when detached from window? Do animations run? Do animations jump to end
- * values? Should they jump to end values? Does requestLayout() get called when detached
- * from window? Probably not; it probably just gets called later when reattached.
- *
- * TODO(newt): use hardware acceleration? See
- * http://blog.danlew.net/2015/10/20/using-hardware-layers-to-improve-animation-performance/
- * and http://developer.android.com/guide/topics/graphics/hardware-accel.html#layers
- *
- * TODO(newt): handle tall infobars on small devices. Use a ScrollView inside the InfoBarWrapper?
- * Make sure InfoBarContainerLayout doesn't extend into tabstrip on tablet.
- *
- * TODO(newt): Disable key events during animations, perhaps by overriding dispatchKeyEvent().
- * Or can we just call setEnabled() false on the infobar wrapper? Will this cause the buttons
- * visual state to change (i.e. to turn gray)?
- *
- * TODO(newt): finalize animation timings and interpolators.
- */
-public class InfoBarContainerLayout extends OptimizedFrameLayout {
- /**
- * Creates an empty InfoBarContainerLayout.
- */
- InfoBarContainerLayout(Context context, Runnable makeContainerVisibleRunnable,
- InfoBarAnimationListener animationListener) {
- super(context, null);
- Resources res = context.getResources();
- mBackInfobarHeight = res.getDimensionPixelSize(R.dimen.infobar_peeking_height);
- mFloatingBehavior = new FloatingBehavior(this);
- mAnimationListener = animationListener;
- mMakeContainerVisibleRunnable = makeContainerVisibleRunnable;
- }
-
- /**
- * Adds an infobar to the container. The infobar appearing animation will happen after the
- * current animation, if any, finishes.
- */
- void addInfoBar(InfoBarUiItem item) {
- mItems.add(findInsertIndex(item), item);
- processPendingAnimations();
- }
-
- /**
- * Finds the appropriate index in the infobar stack for inserting this item.
- * @param item The infobar to be inserted.
- */
- private int findInsertIndex(InfoBarUiItem item) {
- for (int i = 0; i < mItems.size(); ++i) {
- if (item.getPriority() < mItems.get(i).getPriority()) {
- return i;
- }
- }
-
- return mItems.size();
- }
-
- /**
- * Removes an infobar from the container. The infobar will be animated off the screen if it's
- * currently visible.
- */
- void removeInfoBar(InfoBarUiItem item) {
- mItems.remove(item);
- processPendingAnimations();
- }
-
- /**
- * Notifies that an infobar's View ({@link InfoBarUiItem#getView}) has changed. If the infobar
- * is visible in the front of the stack, the infobar will fade out the old contents, resize,
- * then fade in the new contents.
- */
- void notifyInfoBarViewChanged() {
- processPendingAnimations();
- }
-
- /**
- * Returns true if any animations are pending or in progress.
- */
- boolean isAnimating() {
- return mAnimation != null;
- }
-
- /////////////////////////////////////////
- // Implementation details
- /////////////////////////////////////////
-
- /** The maximum number of infobars visible at any time. */
- private static final int MAX_STACK_DEPTH = 3;
-
- // Animation durations.
- private static final int DURATION_SLIDE_UP_MS = 250;
- private static final int DURATION_SLIDE_DOWN_MS = 250;
- private static final int DURATION_FADE_MS = 100;
- private static final int DURATION_FADE_OUT_MS = 200;
-
- /**
- * Base class for animations inside the InfoBarContainerLayout.
- *
- * Provides a standardized way to prepare for, run, and clean up after animations. Each subclass
- * should implement prepareAnimation(), createAnimator(), and onAnimationEnd() as needed.
- */
- private abstract class InfoBarAnimation {
- private Animator mAnimator;
-
- final boolean isStarted() {
- return mAnimator != null;
- }
-
- final void start() {
- Animator.AnimatorListener listener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- InfoBarAnimation.this.onAnimationEnd();
- mAnimation = null;
- mAnimationListener.notifyAnimationFinished(getAnimationType());
- processPendingAnimations();
- }
- };
-
- mAnimator = createAnimator();
- mAnimator.addListener(listener);
- mAnimator.start();
- }
-
- /**
- * Returns an animator that animates an InfoBarWrapper's y-translation from its current
- * value to endValue and updates the side shadow positions on each frame.
- */
- ValueAnimator createTranslationYAnimator(final InfoBarWrapper wrapper, float endValue) {
- ValueAnimator animator = ValueAnimator.ofFloat(wrapper.getTranslationY(), endValue);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- wrapper.setTranslationY((float) animation.getAnimatedValue());
- mFloatingBehavior.updateShadowPosition();
- }
- });
- return animator;
- }
-
- /**
- * Called before the animation begins. This is the time to add views to the hierarchy and
- * adjust layout parameters.
- */
- void prepareAnimation() {}
-
- /**
- * Called to create an Animator which will control the animation. Called after
- * prepareAnimation() and after a subsequent layout has happened.
- */
- abstract Animator createAnimator();
-
- /**
- * Called after the animation completes. This is the time to do post-animation cleanup, such
- * as removing views from the hierarchy.
- */
- void onAnimationEnd() {}
-
- /**
- * Returns the InfoBarAnimationListener.ANIMATION_TYPE_* constant that corresponds to this
- * type of animation (showing, swapping, etc).
- */
- abstract int getAnimationType();
- }
-
- /**
- * The animation to show the first infobar. The infobar slides up from the bottom; then its
- * content fades in.
- */
- private class FirstInfoBarAppearingAnimation extends InfoBarAnimation {
- private InfoBarUiItem mFrontItem;
- private InfoBarWrapper mFrontWrapper;
- private View mFrontContents;
-
- FirstInfoBarAppearingAnimation(InfoBarUiItem frontItem) {
- mFrontItem = frontItem;
- }
-
- @Override
- void prepareAnimation() {
- mFrontContents = mFrontItem.getView();
- mFrontWrapper = new InfoBarWrapper(getContext(), mFrontItem);
- mFrontWrapper.addView(mFrontContents);
- addWrapper(mFrontWrapper);
- }
-
- @Override
- Animator createAnimator() {
- mFrontWrapper.setTranslationY(mFrontWrapper.getHeight());
- mFrontContents.setAlpha(0f);
-
- AnimatorSet animator = new AnimatorSet();
- animator.playSequentially(
- createTranslationYAnimator(mFrontWrapper, 0f).setDuration(DURATION_SLIDE_UP_MS),
- ObjectAnimator.ofFloat(mFrontContents, View.ALPHA, 1f)
- .setDuration(DURATION_FADE_MS));
- return animator;
- }
-
- @Override
- void onAnimationEnd() {
- announceForAccessibility(mFrontItem.getAccessibilityText());
- }
-
- @Override
- int getAnimationType() {
- return InfoBarAnimationListener.ANIMATION_TYPE_SHOW;
- }
- }
-
- /**
- * The animation to show the a new front-most infobar in front of existing visible infobars. The
- * infobar slides up from the bottom; then its content fades in. The previously visible infobars
- * will be resized simulatenously to the new desired size.
- */
- private class FrontInfoBarAppearingAnimation extends InfoBarAnimation {
- private InfoBarUiItem mFrontItem;
- private InfoBarWrapper mFrontWrapper;
- private InfoBarWrapper mOldFrontWrapper;
- private View mFrontContents;
-
- FrontInfoBarAppearingAnimation(InfoBarUiItem frontItem) {
- mFrontItem = frontItem;
- }
-
- @Override
- void prepareAnimation() {
- mOldFrontWrapper = mInfoBarWrappers.get(0);
-
- mFrontContents = mFrontItem.getView();
- mFrontWrapper = new InfoBarWrapper(getContext(), mFrontItem);
- mFrontWrapper.addView(mFrontContents);
- addWrapperToFront(mFrontWrapper);
- }
-
- @Override
- Animator createAnimator() {
- // After adding the new wrapper, the new front item's view, and the old front item's
- // view are both in their wrappers, and the height of the stack as determined by
- // FrameLayout will take both into account. This means the height of the container will
- // be larger than it needs to be, if the previous old front item is larger than the sum
- // of the new front item and mBackInfobarHeight.
- //
- // First work out how much the container will grow or shrink by.
- int heightDelta =
- mFrontWrapper.getHeight() + mBackInfobarHeight - mOldFrontWrapper.getHeight();
-
- // Now work out where to animate the new front item to / from.
- int newFrontStart = mFrontWrapper.getHeight();
- int newFrontEnd = 0;
- if (heightDelta < 0) {
- // If the container is shrinking, this won't be reflected in the layout just yet.
- // The layout will have extra space in it for the previous front infobar, which the
- // animation of the new front infobar has to take into account.
- newFrontStart -= heightDelta;
- newFrontEnd -= heightDelta;
- }
- mFrontWrapper.setTranslationY(newFrontStart);
- mFrontContents.setAlpha(0f);
-
- // Since we are adding the infobar to the top of the stack, make the container fully
- // visible since it could be at hidden or partially hidden state.
- mMakeContainerVisibleRunnable.run();
-
- AnimatorSet animator = new AnimatorSet();
- animator.play(createTranslationYAnimator(mFrontWrapper, newFrontEnd)
- .setDuration(DURATION_SLIDE_UP_MS));
-
- // If the container is shrinking, the back infobars need to animate down (from 0 to the
- // positive delta). Otherwise they have to animate up (from the negative delta to 0).
- int backStart = Math.max(0, heightDelta);
- int backEnd = Math.max(-heightDelta, 0);
- for (int i = 1; i < mInfoBarWrappers.size(); i++) {
- mInfoBarWrappers.get(i).setTranslationY(backStart);
- animator.play(createTranslationYAnimator(mInfoBarWrappers.get(i), backEnd)
- .setDuration(DURATION_SLIDE_UP_MS));
- }
-
- animator.play(ObjectAnimator.ofFloat(mFrontContents, View.ALPHA, 1f)
- .setDuration(DURATION_FADE_MS))
- .after(DURATION_SLIDE_UP_MS);
-
- return animator;
- }
-
- @Override
- void onAnimationEnd() {
- // Remove the old front wrappers view so it won't affect the height of the container any
- // more.
- mOldFrontWrapper.removeAllViews();
-
- // Now set any Y offsets to 0 as there is no need to account for the old front wrapper
- // making the container higher than it should be.
- for (int i = 0; i < mInfoBarWrappers.size(); i++) {
- mInfoBarWrappers.get(i).setTranslationY(0);
- }
- updateLayoutParams();
- announceForAccessibility(mFrontItem.getAccessibilityText());
- }
-
- @Override
- int getAnimationType() {
- return InfoBarAnimationListener.ANIMATION_TYPE_SHOW;
- }
- }
-
- /**
- * The animation to show a back infobar. The infobar slides up behind the existing infobars, so
- * its top edge peeks out just a bit.
- */
- private class BackInfoBarAppearingAnimation extends InfoBarAnimation {
- private InfoBarWrapper mAppearingWrapper;
-
- BackInfoBarAppearingAnimation(InfoBarUiItem appearingItem) {
- mAppearingWrapper = new InfoBarWrapper(getContext(), appearingItem);
- }
-
- @Override
- void prepareAnimation() {
- addWrapper(mAppearingWrapper);
- }
-
- @Override
- Animator createAnimator() {
- mAppearingWrapper.setTranslationY(mAppearingWrapper.getHeight());
- return createTranslationYAnimator(mAppearingWrapper, 0f)
- .setDuration(DURATION_SLIDE_UP_MS);
- }
-
- @Override
- public void onAnimationEnd() {
- mAppearingWrapper.removeView(mAppearingWrapper.getItem().getView());
- }
-
- @Override
- int getAnimationType() {
- return InfoBarAnimationListener.ANIMATION_TYPE_SHOW;
- }
- }
-
- /**
- * The animation to hide the front infobar and reveal the second-to-front infobar. The front
- * infobar slides down and off the screen. The back infobar(s) will adjust to the size of the
- * new front infobar, and then the new front infobar's contents will fade in.
- */
- private class FrontInfoBarDisappearingAndRevealingAnimation extends InfoBarAnimation {
- private InfoBarWrapper mOldFrontWrapper;
- private InfoBarWrapper mNewFrontWrapper;
- private View mNewFrontContents;
-
- @Override
- void prepareAnimation() {
- mOldFrontWrapper = mInfoBarWrappers.get(0);
- mNewFrontWrapper = mInfoBarWrappers.get(1);
- mNewFrontContents = mNewFrontWrapper.getItem().getView();
- mNewFrontWrapper.addView(mNewFrontContents);
- }
-
- @Override
- Animator createAnimator() {
- // The amount by which mNewFrontWrapper will grow (negative value indicates shrinking).
- int deltaHeight = (mNewFrontWrapper.getHeight() - mBackInfobarHeight)
- - mOldFrontWrapper.getHeight();
- int startTranslationY = Math.max(deltaHeight, 0);
- int endTranslationY = Math.max(-deltaHeight, 0);
-
- // Slide the front infobar down and away.
- AnimatorSet animator = new AnimatorSet();
- mOldFrontWrapper.setTranslationY(startTranslationY);
- animator.play(createTranslationYAnimator(
- mOldFrontWrapper, startTranslationY + mOldFrontWrapper.getHeight())
- .setDuration(DURATION_SLIDE_UP_MS));
-
- // Slide the other infobars to their new positions.
- // Note: animator.play() causes these animations to run simultaneously.
- for (int i = 1; i < mInfoBarWrappers.size(); i++) {
- mInfoBarWrappers.get(i).setTranslationY(startTranslationY);
- animator.play(createTranslationYAnimator(mInfoBarWrappers.get(i), endTranslationY)
- .setDuration(DURATION_SLIDE_UP_MS));
- }
-
- mNewFrontContents.setAlpha(0f);
- animator.play(ObjectAnimator.ofFloat(mNewFrontContents, View.ALPHA, 1f)
- .setDuration(DURATION_FADE_MS))
- .after(DURATION_SLIDE_UP_MS);
-
- return animator;
- }
-
- @Override
- void onAnimationEnd() {
- mOldFrontWrapper.removeAllViews();
- removeWrapper(mOldFrontWrapper);
- for (int i = 0; i < mInfoBarWrappers.size(); i++) {
- mInfoBarWrappers.get(i).setTranslationY(0);
- }
- announceForAccessibility(mNewFrontWrapper.getItem().getAccessibilityText());
- }
-
- @Override
- int getAnimationType() {
- return InfoBarAnimationListener.ANIMATION_TYPE_HIDE;
- }
- }
-
- /**
- * The animation to hide the backmost infobar, or the front infobar if there's only one infobar.
- * The infobar simply slides down out of the container.
- */
- private class InfoBarDisappearingAnimation extends InfoBarAnimation {
- private InfoBarWrapper mDisappearingWrapper;
-
- @Override
- void prepareAnimation() {
- mDisappearingWrapper = mInfoBarWrappers.get(mInfoBarWrappers.size() - 1);
- }
-
- @Override
- Animator createAnimator() {
- return createTranslationYAnimator(
- mDisappearingWrapper, mDisappearingWrapper.getHeight())
- .setDuration(DURATION_SLIDE_DOWN_MS);
- }
-
- @Override
- void onAnimationEnd() {
- mDisappearingWrapper.removeAllViews();
- removeWrapper(mDisappearingWrapper);
- }
-
- @Override
- int getAnimationType() {
- return InfoBarAnimationListener.ANIMATION_TYPE_HIDE;
- }
- }
-
- /**
- * The animation to swap the contents of the front infobar. The current contents fade out,
- * then the infobar resizes to fit the new contents, then the new contents fade in.
- */
- private class FrontInfoBarSwapContentsAnimation extends InfoBarAnimation {
- private InfoBarWrapper mFrontWrapper;
- private View mOldContents;
- private View mNewContents;
-
- @Override
- void prepareAnimation() {
- mFrontWrapper = mInfoBarWrappers.get(0);
- mOldContents = mFrontWrapper.getChildAt(0);
- mNewContents = mFrontWrapper.getItem().getView();
- mFrontWrapper.addView(mNewContents);
- }
-
- @Override
- Animator createAnimator() {
- int deltaHeight = mNewContents.getHeight() - mOldContents.getHeight();
- InfoBarContainerLayout.this.setTranslationY(Math.max(0, deltaHeight));
- mNewContents.setAlpha(0f);
-
- AnimatorSet animator = new AnimatorSet();
- animator.playSequentially(ObjectAnimator.ofFloat(mOldContents, View.ALPHA, 0f)
- .setDuration(DURATION_FADE_OUT_MS),
- ObjectAnimator
- .ofFloat(InfoBarContainerLayout.this, View.TRANSLATION_Y,
- Math.max(0, -deltaHeight))
- .setDuration(DURATION_SLIDE_UP_MS),
- ObjectAnimator.ofFloat(mNewContents, View.ALPHA, 1f)
- .setDuration(DURATION_FADE_OUT_MS));
- return animator;
- }
-
- @Override
- void onAnimationEnd() {
- mFrontWrapper.removeViewAt(0);
- InfoBarContainerLayout.this.setTranslationY(0f);
- mFrontWrapper.getItem().setControlsEnabled(true);
- announceForAccessibility(mFrontWrapper.getItem().getAccessibilityText());
- }
-
- @Override
- int getAnimationType() {
- return InfoBarAnimationListener.ANIMATION_TYPE_SWAP;
- }
- }
-
- /**
- * Controls whether infobars fill the full available width, or whether they "float" in the
- * middle of the available space. The latter case happens if the available space is wider than
- * the max width allowed for infobars.
- *
- * Also handles the shadows on the sides of the infobars in floating mode. The side shadows are
- * separate views -- rather than being part of each InfoBarWrapper -- to avoid a double-shadow
- * effect, which would happen during animations when two InfoBarWrappers overlap each other.
- */
- private static class FloatingBehavior {
- /** The InfoBarContainerLayout. */
- private FrameLayout mLayout;
-
- /**
- * The max width of the infobars. If the available space is wider than this, the infobars
- * will switch to floating mode.
- */
- private final int mMaxWidth;
-
- /** The width of the left and right shadows. */
- private final int mShadowWidth;
-
- /** Whether the layout is currently floating. */
- private boolean mIsFloating;
-
- /** The shadows that appear on the sides of the infobars in floating mode. */
- private View mLeftShadowView;
- private View mRightShadowView;
-
- FloatingBehavior(FrameLayout layout) {
- mLayout = layout;
- Resources res = mLayout.getContext().getResources();
- mMaxWidth = res.getDimensionPixelSize(R.dimen.infobar_max_width);
- mShadowWidth = res.getDimensionPixelSize(R.dimen.infobar_shadow_width);
- }
-
- /**
- * This should be called in onMeasure() before super.onMeasure(). The return value is a new
- * widthMeasureSpec that should be passed to super.onMeasure().
- */
- int beforeOnMeasure(int widthMeasureSpec) {
- int width = MeasureSpec.getSize(widthMeasureSpec);
- boolean isFloating = width > mMaxWidth;
- if (isFloating != mIsFloating) {
- mIsFloating = isFloating;
- onIsFloatingChanged();
- }
-
- if (isFloating) {
- int mode = MeasureSpec.getMode(widthMeasureSpec);
- width = Math.min(width, mMaxWidth + 2 * mShadowWidth);
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, mode);
- }
- return widthMeasureSpec;
- }
-
- /**
- * This should be called in onMeasure() after super.onMeasure().
- */
- void afterOnMeasure(int measuredHeight) {
- if (!mIsFloating) return;
- // Measure side shadows to match the parent view's height.
- int widthSpec = MeasureSpec.makeMeasureSpec(mShadowWidth, MeasureSpec.EXACTLY);
- int heightSpec = MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY);
- mLeftShadowView.measure(widthSpec, heightSpec);
- mRightShadowView.measure(widthSpec, heightSpec);
- }
-
- /**
- * This should be called whenever the Y-position of an infobar changes.
- */
- void updateShadowPosition() {
- if (!mIsFloating) return;
- float minY = mLayout.getHeight();
- int childCount = mLayout.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mLayout.getChildAt(i);
- if (child != mLeftShadowView && child != mRightShadowView) {
- minY = Math.min(minY, child.getY());
- }
- }
- mLeftShadowView.setY(minY);
- mRightShadowView.setY(minY);
- }
-
- private void onIsFloatingChanged() {
- if (mIsFloating) {
- initShadowViews();
- mLayout.setPadding(mShadowWidth, 0, mShadowWidth, 0);
- mLayout.setClipToPadding(false);
- mLayout.addView(mLeftShadowView);
- mLayout.addView(mRightShadowView);
- } else {
- mLayout.setPadding(0, 0, 0, 0);
- mLayout.removeView(mLeftShadowView);
- mLayout.removeView(mRightShadowView);
- }
- }
-
- @SuppressLint("RtlHardcoded")
- private void initShadowViews() {
- if (mLeftShadowView != null) return;
-
- mLeftShadowView = new View(mLayout.getContext());
- mLeftShadowView.setBackgroundResource(R.drawable.infobar_shadow_left);
- LayoutParams leftLp = new FrameLayout.LayoutParams(0, 0, Gravity.LEFT);
- leftLp.leftMargin = -mShadowWidth;
- mLeftShadowView.setLayoutParams(leftLp);
-
- mRightShadowView = new View(mLayout.getContext());
- mRightShadowView.setBackgroundResource(R.drawable.infobar_shadow_left);
- LayoutParams rightLp = new FrameLayout.LayoutParams(0, 0, Gravity.RIGHT);
- rightLp.rightMargin = -mShadowWidth;
- mRightShadowView.setScaleX(-1f);
- mRightShadowView.setLayoutParams(rightLp);
- }
- }
-
- /**
- * The height of back infobars, i.e. the distance between the top of the front infobar and the
- * top of the next infobar back.
- */
- private final int mBackInfobarHeight;
-
- /**
- * All the Items, in front to back order.
- * This list is updated immediately when addInfoBar(), removeInfoBar(), and swapInfoBar() are
- * called; so during animations, it does *not* match the currently visible views.
- */
- private final ArrayList<InfoBarUiItem> mItems = new ArrayList<>();
-
- /**
- * The currently visible InfoBarWrappers, in front to back order.
- */
- private final ArrayList<InfoBarWrapper> mInfoBarWrappers = new ArrayList<>();
-
- /** A observer that is notified when animations finish. */
- private final InfoBarAnimationListener mAnimationListener;
-
- /** The current animation, or null if no animation is happening currently. */
- private InfoBarAnimation mAnimation;
-
- private FloatingBehavior mFloatingBehavior;
-
- /** The runnable to make infobar container fully visible. */
- private Runnable mMakeContainerVisibleRunnable;
-
- /**
- * Determines whether any animations need to run in order to make the visible views match the
- * current list of Items in mItems. If so, kicks off the next animation that's needed.
- */
- private void processPendingAnimations() {
- // If an animation is running, wait until it finishes before beginning the next animation.
- if (mAnimation != null) return;
-
- // The steps below are ordered to minimize movement during animations. In particular,
- // removals happen before additions or swaps, and changes are made to back infobars before
- // front infobars.
-
- // First, remove any infobars that are no longer in mItems, if any. Check the back infobars
- // before the front.
- for (int i = mInfoBarWrappers.size() - 1; i >= 0; i--) {
- InfoBarUiItem visibleItem = mInfoBarWrappers.get(i).getItem();
- if (!mItems.contains(visibleItem)) {
- if (i == 0 && mInfoBarWrappers.size() >= 2) {
- // Remove the front infobar and reveal the second-to-front infobar.
- runAnimation(new FrontInfoBarDisappearingAndRevealingAnimation());
- return;
-
- } else {
- // Move the infobar to the very back if it's not already there.
- InfoBarWrapper wrapper = mInfoBarWrappers.get(i);
- if (i != mInfoBarWrappers.size() - 1) {
- removeWrapper(wrapper);
- addWrapper(wrapper);
- }
-
- // Remove the backmost infobar (which may be the front infobar).
- runAnimation(new InfoBarDisappearingAnimation());
- return;
- }
- }
- }
-
- // Second, run swap animation on front infobar if needed.
- if (!mInfoBarWrappers.isEmpty()) {
- InfoBarUiItem frontItem = mInfoBarWrappers.get(0).getItem();
- View frontContents = mInfoBarWrappers.get(0).getChildAt(0);
- if (frontContents != frontItem.getView()) {
- runAnimation(new FrontInfoBarSwapContentsAnimation());
- return;
- }
- }
-
- // Third, check if we should add any infobars in front of visible infobars. This can happen
- // if an infobar has been inserted into mItems, in front of the currently visible item. To
- // detect this the items at the beginning of mItems are compared against the first item in
- // mInfoBarWrappers.
- if (!mInfoBarWrappers.isEmpty()) {
- // Find the infobar with the highest index that isn't currently being shown.
- InfoBarUiItem currentVisibleItem = mInfoBarWrappers.get(0).getItem();
- InfoBarUiItem itemToInsert = null;
- for (int checkIndex = 0; checkIndex < mItems.size(); checkIndex++) {
- if (mItems.get(checkIndex) == currentVisibleItem) {
- // There are no remaining infobars that can possibly override the
- // currently displayed one.
- break;
- } else {
- // Found an infobar that isn't being displayed yet. Track it so that
- // it can be animated in.
- itemToInsert = mItems.get(checkIndex);
- }
- }
- if (itemToInsert != null) {
- runAnimation(new FrontInfoBarAppearingAnimation(itemToInsert));
- return;
- }
- }
-
- // Fourth, check if we should add any infobars at the back.
- int desiredChildCount = Math.min(mItems.size(), MAX_STACK_DEPTH);
- if (mInfoBarWrappers.size() < desiredChildCount) {
- InfoBarUiItem itemToShow = mItems.get(mInfoBarWrappers.size());
- runAnimation(mInfoBarWrappers.isEmpty()
- ? new FirstInfoBarAppearingAnimation(itemToShow)
- : new BackInfoBarAppearingAnimation(itemToShow));
- return;
- }
-
- // Fifth, now that we've stabilized, let listeners know that we have no more animations.
- InfoBarUiItem frontItem =
- mInfoBarWrappers.size() > 0 ? mInfoBarWrappers.get(0).getItem() : null;
- mAnimationListener.notifyAllAnimationsFinished(frontItem);
- }
-
- private void runAnimation(InfoBarAnimation animation) {
- mAnimation = animation;
- mAnimation.prepareAnimation();
- if (isLayoutRequested()) {
- // onLayout() will call mAnimation.start().
- } else {
- mAnimation.start();
- }
- }
-
- private void addWrapper(InfoBarWrapper wrapper) {
- addView(wrapper, 0, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
- mInfoBarWrappers.add(wrapper);
- updateLayoutParams();
- }
-
- private void addWrapperToFront(InfoBarWrapper wrapper) {
- addView(wrapper, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
- mInfoBarWrappers.add(0, wrapper);
- updateLayoutParams();
- }
-
- private void removeWrapper(InfoBarWrapper wrapper) {
- removeView(wrapper);
- mInfoBarWrappers.remove(wrapper);
- updateLayoutParams();
- }
-
- private void updateLayoutParams() {
- // Stagger the top margins so the back infobars peek out a bit.
- int childCount = mInfoBarWrappers.size();
- for (int i = 0; i < childCount; i++) {
- View child = mInfoBarWrappers.get(i);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.topMargin = (childCount - 1 - i) * mBackInfobarHeight;
- child.setLayoutParams(lp);
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- widthMeasureSpec = mFloatingBehavior.beforeOnMeasure(widthMeasureSpec);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- mFloatingBehavior.afterOnMeasure(getMeasuredHeight());
- }
-
- @Override
- public void announceForAccessibility(CharSequence text) {
- if (TextUtils.isEmpty(text)) return;
- super.announceForAccessibility(text);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- mFloatingBehavior.updateShadowPosition();
-
- // Animations start after a layout has completed, at which point all views are guaranteed
- // to have valid sizes and positions.
- if (mAnimation != null && !mAnimation.isStarted()) {
- mAnimation.start();
- }
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // Trap any attempts to fiddle with the infobars while we're animating.
- return super.onInterceptTouchEvent(ev) || mAnimation != null
- || (!mInfoBarWrappers.isEmpty()
- && !mInfoBarWrappers.get(0).getItem().areControlsEnabled());
- }
-
- @Override
- @SuppressLint("ClickableViewAccessibility")
- public boolean onTouchEvent(MotionEvent event) {
- super.onTouchEvent(event);
- // Consume all touch events so they do not reach the ContentView.
- return true;
- }
-
- @Override
- public boolean onHoverEvent(MotionEvent event) {
- super.onHoverEvent(event);
- // Consume all hover events so they do not reach the ContentView. In touch exploration mode,
- // this prevents the user from interacting with the part of the ContentView behind the
- // infobars. http://crbug.com/430701
- return true;
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java
index 553608310f2..377ea4d0d4f 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java
@@ -17,6 +17,11 @@ import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.MathUtils;
+import org.chromium.components.browser_ui.banners.SwipableOverlayView;
+import org.chromium.components.infobars.InfoBar;
+import org.chromium.components.infobars.InfoBarAnimationListener;
+import org.chromium.components.infobars.InfoBarContainerLayout;
+import org.chromium.components.infobars.InfoBarUiItem;
import org.chromium.ui.display.DisplayAndroid;
import org.chromium.ui.display.DisplayUtil;
@@ -27,7 +32,7 @@ public class InfoBarContainerView extends SwipableOverlayView {
/**
* Observes container view changes.
*/
- public interface ContainerViewObserver extends InfoBarContainer.InfoBarAnimationListener {
+ public interface ContainerViewObserver extends InfoBarAnimationListener {
/**
* Called when the height of shown content changed.
* @param shownFraction The ratio of height of shown content to the height of the container
@@ -82,8 +87,8 @@ public class InfoBarContainerView extends SwipableOverlayView {
updateLayoutParams(context, isTablet);
Runnable makeContainerVisibleRunnable = () -> runUpEventAnimation(true);
- mLayout = new InfoBarContainerLayout(context, makeContainerVisibleRunnable,
- new InfoBarContainer.InfoBarAnimationListener() {
+ mLayout = new InfoBarContainerLayout(
+ context, makeContainerVisibleRunnable, new InfoBarAnimationListener() {
@Override
public void notifyAnimationFinished(int animationType) {
mContainerViewObserver.notifyAnimationFinished(animationType);
@@ -187,7 +192,7 @@ public class InfoBarContainerView extends SwipableOverlayView {
void addToParentView() {
// If mTab is null, destroy() was called. This should not be added after destroyed.
assert mTab != null;
- super.addToParentView(mParentView,
+ super.addToParentViewAtIndex(mParentView,
mTab.getBrowser().getViewController().getDesiredInfoBarContainerViewIndex());
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarUiItem.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarUiItem.java
deleted file mode 100644
index 5a653d069c3..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarUiItem.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.view.View;
-
-import androidx.annotation.IntDef;
-
-import org.chromium.chrome.browser.infobar.InfoBarIdentifier;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * An interface for items that can be added to an InfoBarContainerLayout.
- */
-public interface InfoBarUiItem {
- // The infobar priority.
- @IntDef({InfoBarPriority.CRITICAL, InfoBarPriority.USER_TRIGGERED,
- InfoBarPriority.PAGE_TRIGGERED, InfoBarPriority.BACKGROUND})
- @Retention(RetentionPolicy.SOURCE)
- public @interface InfoBarPriority {
- int CRITICAL = 0;
- int USER_TRIGGERED = 1;
- int PAGE_TRIGGERED = 2;
- int BACKGROUND = 3;
- }
-
- /**
- * Returns the View that represents this infobar. This should have no background or borders;
- * a background and shadow will be added by a wrapper view.
- */
- View getView();
-
- /**
- * Returns whether controls for this View should be clickable. If false, all input events on
- * this item will be ignored.
- */
- boolean areControlsEnabled();
-
- /**
- * Sets whether or not controls for this View should be clickable. This does not affect the
- * visual state of the infobar.
- * @param state If false, all input events on this Item will be ignored.
- */
- void setControlsEnabled(boolean state);
-
- /**
- * Returns the accessibility text to announce when this infobar is first shown.
- */
- CharSequence getAccessibilityText();
-
- /**
- * Returns the priority of an infobar. High priority infobar is shown in front of low
- * priority infobar. If infobars have the same priorities, the most recently added one
- * is shown behind previous ones.
- *
- */
- int getPriority();
-
- /**
- * Returns the type of infobar, as best as can be determined at this time. See
- * components/infobars/core/infobar_delegate.h.
- */
- @InfoBarIdentifier
- int getInfoBarIdentifier();
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarWrapper.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarWrapper.java
deleted file mode 100644
index 8a574254a96..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarWrapper.java
+++ /dev/null
@@ -1,44 +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.
-
-package org.chromium.weblayer_private;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.FrameLayout;
-
-/**
- * Layout that holds an infobar's contents and provides a background color and a top shadow.
- */
-class InfoBarWrapper extends FrameLayout {
- private final InfoBarUiItem mItem;
-
- /**
- * Constructor for inflating from Java.
- */
- InfoBarWrapper(Context context, InfoBarUiItem item) {
- super(context);
- mItem = item;
- Resources res = context.getResources();
- int peekingHeight = res.getDimensionPixelSize(R.dimen.infobar_peeking_height);
- int shadowHeight = res.getDimensionPixelSize(R.dimen.infobar_shadow_height);
- setMinimumHeight(peekingHeight + shadowHeight);
-
- // setBackgroundResource() changes the padding, so call setPadding() second.
- setBackgroundResource(R.drawable.weblayer_infobar_wrapper_bg);
- setPadding(0, shadowHeight, 0, 0);
- }
-
- InfoBarUiItem getItem() {
- return mItem;
- }
-
- @Override
- public void onViewAdded(View child) {
- child.setLayoutParams(new LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.TOP));
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java
index 32f947fb86e..7a9a7303418 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java
@@ -28,6 +28,7 @@ public class InterceptNavigationDelegateClientImpl implements InterceptNavigatio
private RedirectHandler mRedirectHandler;
private InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
private long mLastNavigationWithUserGestureTime = RedirectHandler.INVALID_TIME;
+ private boolean mDestroyed;
InterceptNavigationDelegateClientImpl(TabImpl tab) {
mTab = tab;
@@ -53,6 +54,7 @@ public class InterceptNavigationDelegateClientImpl implements InterceptNavigatio
}
public void destroy() {
+ mDestroyed = true;
getWebContents().removeObserver(mWebContentsObserver);
mInterceptNavigationDelegate.associateWithWebContents(null);
}
@@ -118,6 +120,11 @@ public class InterceptNavigationDelegateClientImpl implements InterceptNavigatio
@Override
public void closeTab() {
+ // When InterceptNavigationDelegate determines that a tab needs to be closed, it posts a
+ // task invoking this method. It is possible that in the interim the tab was closed for
+ // another reason. In that case there is nothing more to do here.
+ if (mDestroyed) return;
+
closeTab(mTab);
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaSessionManager.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaSessionManager.java
index a36125ace70..bd5934aff36 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaSessionManager.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaSessionManager.java
@@ -12,10 +12,10 @@ import android.support.v4.media.session.MediaSessionCompat;
import org.chromium.components.browser_ui.media.MediaNotificationController;
import org.chromium.components.browser_ui.media.MediaNotificationInfo;
import org.chromium.components.browser_ui.media.MediaSessionHelper;
-import org.chromium.components.browser_ui.notifications.ChromeNotification;
-import org.chromium.components.browser_ui.notifications.ChromeNotificationBuilder;
import org.chromium.components.browser_ui.notifications.ForegroundServiceUtils;
import org.chromium.components.browser_ui.notifications.NotificationMetadata;
+import org.chromium.components.browser_ui.notifications.NotificationWrapper;
+import org.chromium.components.browser_ui.notifications.NotificationWrapperBuilder;
/**
* A glue class for MediaSession.
@@ -28,7 +28,7 @@ class MediaSessionManager {
@SuppressLint("StaticFieldLeak")
static MediaNotificationController sController;
- private static int sNotificationId = 0;
+ private static int sNotificationId;
static void serviceStarted(Service service, Intent intent) {
if (sController != null && sController.processIntent(service, intent)) return;
@@ -37,7 +37,7 @@ class MediaSessionManager {
// notification hasn't been shown. See similar logic in {@link
// ChromeMediaNotificationControllerDelegate}.
MediaNotificationController.finishStartingForegroundServiceOnO(
- service, createChromeNotificationBuilder().buildChromeNotification());
+ service, createNotificationWrapperBuilder().buildNotificationWrapper());
// Call stopForeground to guarantee Android unset the foreground bit.
ForegroundServiceUtils.getInstance().stopForeground(
service, Service.STOP_FOREGROUND_REMOVE);
@@ -109,8 +109,8 @@ class MediaSessionManager {
}
@Override
- public ChromeNotificationBuilder createChromeNotificationBuilder() {
- return MediaSessionManager.createChromeNotificationBuilder();
+ public NotificationWrapperBuilder createNotificationWrapperBuilder() {
+ return MediaSessionManager.createNotificationWrapperBuilder();
}
@Override
@@ -119,17 +119,17 @@ class MediaSessionManager {
}
@Override
- public void logNotificationShown(ChromeNotification notification) {}
+ public void logNotificationShown(NotificationWrapper notification) {}
}
- private static ChromeNotificationBuilder createChromeNotificationBuilder() {
+ private static NotificationWrapperBuilder createNotificationWrapperBuilder() {
ensureNotificationId();
// Only the null tag will work as expected, because {@link Service#startForeground()} only
// takes an ID and no tag. If we pass a tag here, then the notification that's used to
// display a paused state (no foreground service) will not be identified as the same one
// that's used with the foreground service.
- return WebLayerNotificationBuilder.create(
+ return WebLayerNotificationWrapperBuilder.create(
WebLayerNotificationChannels.ChannelId.MEDIA_PLAYBACK,
new NotificationMetadata(0, null /*notificationTag*/, sNotificationId));
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaStreamManager.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaStreamManager.java
index 90925f10df5..99232d8d698 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaStreamManager.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/MediaStreamManager.java
@@ -13,13 +13,14 @@ import android.util.AndroidRuntimeException;
import android.webkit.ValueCallback;
import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
-import org.chromium.components.browser_ui.notifications.ChromeNotification;
import org.chromium.components.browser_ui.notifications.NotificationManagerProxy;
import org.chromium.components.browser_ui.notifications.NotificationManagerProxyImpl;
import org.chromium.components.browser_ui.notifications.NotificationMetadata;
+import org.chromium.components.browser_ui.notifications.NotificationWrapper;
import org.chromium.components.browser_ui.notifications.PendingIntentProvider;
import org.chromium.components.webrtc.MediaCaptureNotificationUtil;
import org.chromium.components.webrtc.MediaCaptureNotificationUtil.MediaType;
@@ -178,6 +179,7 @@ public class MediaStreamManager {
audio, video, ObjectWrapper.wrap(new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean allowed) {
+ ThreadUtils.assertOnUiThread();
respondToStreamRequest(requestId, allowed.booleanValue());
}
}));
@@ -223,12 +225,13 @@ public class MediaStreamManager {
int mediaType = audio && video ? MediaType.AUDIO_AND_VIDEO
: audio ? MediaType.AUDIO_ONLY : MediaType.VIDEO_ONLY;
- // TODO(crbug/1076098): don't pass a URL in incognito.
- ChromeNotification notification = MediaCaptureNotificationUtil.createNotification(
- WebLayerNotificationBuilder.create(
+ NotificationWrapper notification = MediaCaptureNotificationUtil.createNotification(
+ WebLayerNotificationWrapperBuilder.create(
WebLayerNotificationChannels.ChannelId.WEBRTC_CAM_AND_MIC,
new NotificationMetadata(0, AV_STREAM_TAG, mNotificationId)),
- mediaType, mTab.getWebContents().getVisibleUrl().getSpec(),
+ mediaType,
+ mTab.getProfile().isIncognito() ? null
+ : mTab.getWebContents().getVisibleUrl().getSpec(),
WebLayerImpl.getClientApplicationName(), contentIntent, null /*stopIntent*/);
getNotificationManager().notify(notification);
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
index 3957ed46557..31303359040 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
@@ -36,12 +36,18 @@ public final class NavigationControllerImpl extends INavigationController.Stub {
if (WebLayerFactoryImpl.getClientMajorVersion() < 83) {
assert params == null;
}
- if (params == null) {
- NavigationControllerImplJni.get().navigate(mNativeNavigationController, uri);
- } else {
- NavigationControllerImplJni.get().navigateWithParams(
- mNativeNavigationController, uri, params.mShouldReplaceCurrentEntry);
- }
+ navigate2(uri, params == null ? false : params.mShouldReplaceCurrentEntry, false, false,
+ false);
+ }
+
+ @Override
+ public void navigate2(String uri, boolean shouldReplaceCurrentEntry,
+ boolean disableIntentProcessing, boolean disableNetworkErrorAutoReload,
+ boolean enableAutoPlay) throws RemoteException {
+ StrictModeWorkaround.apply();
+ NavigationControllerImplJni.get().navigate(mNativeNavigationController, uri,
+ shouldReplaceCurrentEntry, disableIntentProcessing, disableNetworkErrorAutoReload,
+ enableAutoPlay);
}
@Override
@@ -177,9 +183,9 @@ public final class NavigationControllerImpl extends INavigationController.Stub {
void setNavigationControllerImpl(
long nativeNavigationControllerImpl, NavigationControllerImpl caller);
long getNavigationController(long tab);
- void navigate(long nativeNavigationControllerImpl, String uri);
- void navigateWithParams(
- long nativeNavigationControllerImpl, String uri, boolean shouldReplaceCurrentEntry);
+ void navigate(long nativeNavigationControllerImpl, String uri,
+ boolean shouldReplaceCurrentEntry, boolean disableIntentProcessing,
+ boolean disableNetworkErrorAutoReload, boolean enableAutoPlay);
void goBack(long nativeNavigationControllerImpl);
void goForward(long nativeNavigationControllerImpl);
boolean canGoBack(long nativeNavigationControllerImpl);
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
index cff0bc6b92d..7815edb19f1 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
@@ -147,6 +147,20 @@ public final class NavigationImpl extends INavigation.Stub {
return NavigationImplJni.get().wasStopCalled(mNativeNavigationImpl);
}
+ @Override
+ public boolean isPageInitiated() {
+ StrictModeWorkaround.apply();
+ throwIfNativeDestroyed();
+ return NavigationImplJni.get().isPageInitiated(mNativeNavigationImpl);
+ }
+
+ @Override
+ public boolean isReload() {
+ StrictModeWorkaround.apply();
+ throwIfNativeDestroyed();
+ return NavigationImplJni.get().isReload(mNativeNavigationImpl);
+ }
+
private void throwIfNativeDestroyed() {
if (mNativeNavigationImpl == 0) {
throw new IllegalStateException("Using Navigation after native destroyed");
@@ -195,5 +209,7 @@ public final class NavigationImpl extends INavigation.Stub {
boolean isValidRequestHeaderName(String name);
boolean isValidRequestHeaderValue(String value);
boolean setUserAgentString(long nativeNavigationImpl, String value);
+ boolean isPageInitiated(long nativeNavigationImpl);
+ boolean isReload(long nativeNavigationImpl);
}
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NewTabCallbackProxy.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NewTabCallbackProxy.java
index 25645acdc76..a547f633d99 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NewTabCallbackProxy.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NewTabCallbackProxy.java
@@ -52,7 +52,7 @@ public final class NewTabCallbackProxy {
// This class should only be created while the tab is attached to a fragment.
assert mTab.getBrowser() != null;
assert mTab.getBrowser().equals(tab.getBrowser());
- mTab.getClient().onNewTab(tab.getId(), mode);
+ mTab.getClient().onNewTab(tab.getId(), implTypeToJavaType(mode));
}
@CalledByNative
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java
index 314b6b7ff29..e9ff295181c 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java
@@ -11,8 +11,10 @@ import androidx.annotation.NonNull;
import org.chromium.base.StrictModeContext;
import org.chromium.base.supplier.Supplier;
+import org.chromium.components.browser_ui.site_settings.SiteSettingsClient;
import org.chromium.components.content_settings.CookieControlsBridge;
import org.chromium.components.content_settings.CookieControlsObserver;
+import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.page_info.PageInfoControllerDelegate;
import org.chromium.content_public.browser.WebContents;
@@ -26,7 +28,7 @@ import org.chromium.weblayer_private.interfaces.SiteSettingsIntentHelper;
public class PageInfoControllerDelegateImpl extends PageInfoControllerDelegate {
private final Context mContext;
private final WebContents mWebContents;
- private final String mProfileName;
+ private final ProfileImpl mProfile;
static PageInfoControllerDelegateImpl create(WebContents webContents) {
TabImpl tab = TabImpl.fromWebContents(webContents);
@@ -45,7 +47,7 @@ public class PageInfoControllerDelegateImpl extends PageInfoControllerDelegate {
CookieControlsBridge.isCookieControlsEnabled(profile));
mContext = context;
mWebContents = webContents;
- mProfileName = profile.getName();
+ mProfile = profile;
}
/**
@@ -53,8 +55,8 @@ public class PageInfoControllerDelegateImpl extends PageInfoControllerDelegate {
*/
@Override
public void showSiteSettings(String url) {
- Intent intent =
- SiteSettingsIntentHelper.createIntentForSingleWebsite(mContext, mProfileName, url);
+ Intent intent = SiteSettingsIntentHelper.createIntentForSingleWebsite(
+ mContext, mProfile.getName(), url);
// Disabling StrictMode to avoid violations (https://crbug.com/819410).
try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
@@ -71,6 +73,24 @@ public class PageInfoControllerDelegateImpl extends PageInfoControllerDelegate {
return new CookieControlsBridge(observer, mWebContents, null);
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @NonNull
+ public BrowserContextHandle getBrowserContext() {
+ return mProfile;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @NonNull
+ public SiteSettingsClient getSiteSettingsClient() {
+ return new WebLayerSiteSettingsClient(getBrowserContext());
+ }
+
private static boolean isHttpOrHttps(GURL url) {
String scheme = url.getScheme();
return UrlConstants.HTTP_SCHEME.equals(scheme) || UrlConstants.HTTPS_SCHEME.equals(scheme);
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java
index c359dc3513d..c5246c384fd 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java
@@ -5,6 +5,7 @@
package org.chromium.weblayer_private;
import android.content.Intent;
+import android.graphics.Bitmap;
import android.text.TextUtils;
import android.webkit.ValueCallback;
@@ -206,6 +207,16 @@ public final class ProfileImpl extends IProfile.Stub implements BrowserContextHa
ProfileImplJni.get().prepareForPossibleCrossOriginNavigation(mNativeProfile);
}
+ @Override
+ public void getCachedFaviconForPageUri(@NonNull String uri, @NonNull IObjectWrapper callback) {
+ StrictModeWorkaround.apply();
+ checkNotDestroyed();
+ ValueCallback<Bitmap> valueCallback =
+ (ValueCallback<Bitmap>) ObjectWrapper.unwrap(callback, ValueCallback.class);
+ Callback<Bitmap> baseCallback = valueCallback::onReceiveValue;
+ ProfileImplJni.get().getCachedFaviconForPageUrl(mNativeProfile, uri, baseCallback);
+ }
+
void checkNotDestroyed() {
if (!mBeingDeleted) return;
throw new IllegalArgumentException("Profile being destroyed: " + mName);
@@ -224,6 +235,9 @@ public final class ProfileImpl extends IProfile.Stub implements BrowserContextHa
case BrowsingDataType.CACHE:
convertedTypes.add(ImplBrowsingDataType.CACHE);
break;
+ case BrowsingDataType.SITE_SETTINGS:
+ convertedTypes.add(ImplBrowsingDataType.SITE_SETTINGS);
+ break;
default:
break; // Skip unrecognized values for forward compatibility.
}
@@ -274,5 +288,7 @@ public final class ProfileImpl extends IProfile.Stub implements BrowserContextHa
void removeBrowserPersistenceStorage(
long nativeProfileImpl, String[] ids, Callback<Boolean> callback);
void prepareForPossibleCrossOriginNavigation(long nativeProfileImpl);
+ void getCachedFaviconForPageUrl(
+ long nativeProfileImpl, String url, Callback<Bitmap> callback);
}
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/SiteSettingsFragmentImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/SiteSettingsFragmentImpl.java
index 072df069fb9..b42613ee17a 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/SiteSettingsFragmentImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/SiteSettingsFragmentImpl.java
@@ -7,13 +7,17 @@ package org.chromium.weblayer_private;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
+import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
+import android.view.ViewStub;
import android.view.Window;
import androidx.appcompat.app.AppCompatDelegate;
@@ -38,6 +42,8 @@ import org.chromium.weblayer_private.interfaces.SiteSettingsFragmentArgs;
import org.chromium.weblayer_private.interfaces.SiteSettingsIntentHelper;
import org.chromium.weblayer_private.interfaces.StrictModeWorkaround;
+import java.lang.reflect.Constructor;
+
/**
* WebLayer's implementation of the client library's SiteSettingsFragment.
*
@@ -77,11 +83,19 @@ public class SiteSettingsFragmentImpl extends RemoteFragmentImpl {
*/
private static class PassthroughFragmentActivity extends FragmentActivity
implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
+ private static final Class<?>[] VIEW_CONSTRUCTOR_ARGS =
+ new Class[] {Context.class, AttributeSet.class};
+
private final SiteSettingsFragmentImpl mFragmentImpl;
private PassthroughFragmentActivity(SiteSettingsFragmentImpl fragmentImpl) {
mFragmentImpl = fragmentImpl;
attachBaseContext(mFragmentImpl.getWebLayerContext());
+ // Register ourselves as a the LayoutInflater factory so we can handle loading Views.
+ // See onCreateView for information about why this is needed.
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
+ getLayoutInflater().setFactory2(this);
+ }
// This class doesn't extend AppCompatActivity, so some appcompat functionality doesn't
// get initialized, which leads to some appcompat widgets (like switches) rendering
// incorrectly. There are some resource issues with having this class extend
@@ -104,6 +118,54 @@ public class SiteSettingsFragmentImpl extends RemoteFragmentImpl {
Context.LAYOUT_INFLATER_SERVICE);
}
+ // This method is needed to work around a LayoutInflater bug in Android <N. Before
+ // LayoutInflater creates an instance of a View, it needs to look up the class by name to
+ // get a reference to its Constructor. As an optimization, it caches this name to
+ // Constructor mapping. This cache causes issues if a class gets loaded multiple times with
+ // different ClassLoaders. In Site Settings, some AndroidX Views get loaded early on with
+ // the embedding app's ClassLoader, so the Constructor from that ClassLoader's version of
+ // the class gets cached. When the WebLayer implementation later tries to inflate the same
+ // class, it instantiates a version from the wrong ClassLoader, which leads to a
+ // ClassCastException when casting that View to its original class. This was fixed in
+ // Android N, but to work around it on L & M, we inflate the Views manually here, which
+ // bypasses LayoutInflater's cache.
+ @Override
+ public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+ // If the class doesn't have a '.' in its name, it's probably a built-in Android View,
+ // which are often referenced by just their class names with no package prefix. For
+ // these classes we can return null to fall back to LayoutInflater's default behavior.
+ if (name.indexOf('.') == -1) {
+ return null;
+ }
+
+ Class<? extends View> clazz = null;
+ try {
+ clazz = context.getClassLoader().loadClass(name).asSubclass(View.class);
+ LayoutInflater inflater = getLayoutInflater();
+ if (inflater.getFilter() != null && !inflater.getFilter().onLoadClass(clazz)) {
+ throw new InflateException(attrs.getPositionDescription()
+ + ": Class not allowed to be inflated " + name);
+ }
+
+ Constructor<? extends View> constructor =
+ clazz.getConstructor(VIEW_CONSTRUCTOR_ARGS);
+ constructor.setAccessible(true);
+ View view = constructor.newInstance(new Object[] {context, attrs});
+ if (view instanceof ViewStub) {
+ // Use the same Context when inflating ViewStub later.
+ ViewStub viewStub = (ViewStub) view;
+ viewStub.setLayoutInflater(inflater.cloneInContext(context));
+ }
+ return view;
+ } catch (Exception e) {
+ InflateException ie = new InflateException(attrs.getPositionDescription()
+ + ": Error inflating class "
+ + (clazz == null ? "<unknown>" : clazz.getName()));
+ ie.initCause(e);
+ throw ie;
+ }
+ }
+
@Override
public Window getWindow() {
return getEmbedderActivity().getWindow();
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/SwipableOverlayView.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/SwipableOverlayView.java
deleted file mode 100644
index 7f46f8afcd2..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/SwipableOverlayView.java
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Region;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
-
-import androidx.annotation.IntDef;
-
-import org.chromium.base.MathUtils;
-import org.chromium.content_public.browser.GestureListenerManager;
-import org.chromium.content_public.browser.GestureStateListenerWithScroll;
-import org.chromium.content_public.browser.WebContents;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * View that slides up from the bottom of the page and slides away as the user scrolls the page.
- * Meant to be tacked onto the {@link org.chromium.content_public.browser.WebContents}'s view and
- * alerted when either the page scroll position or viewport size changes.
- *
- * GENERAL BEHAVIOR
- * This View is brought onto the screen by sliding upwards from the bottom of the screen. Afterward
- * the View slides onto and off of the screen vertically as the user scrolls upwards or
- * downwards on the page.
- *
- * As the scroll offset or the viewport height are updated via a scroll or fling, the difference
- * from the initial value is used to determine the View's Y-translation. If a gesture is stopped,
- * the View will be snapped back into the center of the screen or entirely off of the screen, based
- * on how much of the View is visible, or where the user is currently located on the page.
- */
-public abstract class SwipableOverlayView extends FrameLayout {
- private static final float FULL_THRESHOLD = 0.5f;
- private static final float VERTICAL_FLING_SHOW_THRESHOLD = 0.2f;
- private static final float VERTICAL_FLING_HIDE_THRESHOLD = 0.9f;
-
- @IntDef({Gesture.NONE, Gesture.SCROLLING, Gesture.FLINGING})
- @Retention(RetentionPolicy.SOURCE)
- private @interface Gesture {
- int NONE = 0;
- int SCROLLING = 1;
- int FLINGING = 2;
- }
-
- private static final long ANIMATION_DURATION_MS = 250;
-
- /** Detects when the user is dragging the WebContents. */
- private final GestureStateListenerWithScroll mGestureStateListener;
-
- /** Listens for changes in the layout. */
- private final View.OnLayoutChangeListener mLayoutChangeListener;
-
- /** Interpolator used for the animation. */
- private final Interpolator mInterpolator;
-
- /** Tracks whether the user is scrolling or flinging. */
- private @Gesture int mGestureState;
-
- /** Animation currently being used to translate the View. */
- private Animator mCurrentAnimation;
-
- /** Used to determine when the layout has changed and the Viewport must be updated. */
- private int mParentHeight;
-
- /** Offset from the top of the page when the current gesture was first started. */
- private int mInitialOffsetY;
-
- /** How tall the View is, including its margins. */
- private int mTotalHeight;
-
- /** Whether or not the View ever been fully displayed. */
- private boolean mIsBeingDisplayedForFirstTime;
-
- /** The WebContents to which the overlay is added. */
- private WebContents mWebContents;
-
- /**
- * Creates a SwipableOverlayView.
- * @param context Context for acquiring resources.
- * @param attrs Attributes from the XML layout inflation.
- */
- public SwipableOverlayView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mGestureStateListener = createGestureStateListener();
- mGestureState = Gesture.NONE;
- mLayoutChangeListener = createLayoutChangeListener();
- mInterpolator = new DecelerateInterpolator(1.0f);
-
- // We make this view 'draw' to provide a placeholder for its animations.
- setWillNotDraw(false);
- }
-
- /**
- * Set the given WebContents for scrolling changes.
- */
- public void setWebContents(WebContents webContents) {
- if (mWebContents != null) {
- GestureListenerManager.fromWebContents(mWebContents)
- .removeListener(mGestureStateListener);
- }
-
- mWebContents = webContents;
- // See comment in onLayout() as to why the listener is only attached if mTotalHeight is > 0.
- if (mWebContents != null && mTotalHeight > 0) {
- GestureListenerManager.fromWebContents(mWebContents).addListener(mGestureStateListener);
- }
- }
-
- public WebContents getWebContents() {
- return mWebContents;
- }
-
- protected void addToParentView(ViewGroup parentView, int index) {
- if (parentView == null) return;
- if (getParent() == null) {
- parentView.addView(this, index, createLayoutParams());
-
- // Listen for the layout to know when to animate the View coming onto the screen.
- addOnLayoutChangeListener(mLayoutChangeListener);
- }
- }
-
- /**
- * Removes the SwipableOverlayView from its parent and stops monitoring the WebContents.
- * @return Whether the View was removed from its parent.
- */
- public boolean removeFromParentView() {
- if (getParent() == null) return false;
-
- ((ViewGroup) getParent()).removeView(this);
- removeOnLayoutChangeListener(mLayoutChangeListener);
- return true;
- }
-
- /**
- * Creates a set of LayoutParams that makes the View hug the bottom of the screen. Override it
- * for other types of behavior.
- * @return LayoutParams for use when adding the View to its parent.
- */
- public ViewGroup.MarginLayoutParams createLayoutParams() {
- return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
- Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (!isAllowedToAutoHide()) setTranslationY(0.0f);
- }
-
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- super.onWindowFocusChanged(hasWindowFocus);
- if (!isAllowedToAutoHide()) setTranslationY(0.0f);
- }
-
- /**
- * See {@link #android.view.ViewGroup.onLayout(boolean, int, int, int, int)}.
- */
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- // Update the viewport height when the parent View's height changes (e.g. after rotation).
- int currentParentHeight = getParent() == null ? 0 : ((View) getParent()).getHeight();
- if (mParentHeight != currentParentHeight) {
- mParentHeight = currentParentHeight;
- mGestureState = Gesture.NONE;
- if (mCurrentAnimation != null) mCurrentAnimation.end();
- }
-
- // Update the known effective height of the View.
- MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
- mTotalHeight = getMeasuredHeight() + params.topMargin + params.bottomMargin;
-
- // Adding a listener to GestureListenerManager results in extra IPCs on every frame, which
- // is very costly. Only attach the listener if needed.
- if (mWebContents != null) {
- if (mTotalHeight > 0) {
- GestureListenerManager.fromWebContents(mWebContents)
- .addListener(mGestureStateListener);
- } else {
- GestureListenerManager.fromWebContents(mWebContents)
- .removeListener(mGestureStateListener);
- }
- }
-
- super.onLayout(changed, l, t, r, b);
- }
-
- /**
- * Creates a listener than monitors the WebContents for scrolls and flings.
- * The listener updates the location of this View to account for the user's gestures.
- * @return GestureStateListenerWithScroll to send to the WebContents.
- */
- private GestureStateListenerWithScroll createGestureStateListener() {
- return new GestureStateListenerWithScroll() {
- /** Tracks the previous event's scroll offset to determine if a scroll is up or down. */
- private int mLastScrollOffsetY;
-
- /** Location of the View when the current gesture was first started. */
- private float mInitialTranslationY;
-
- /** The initial extent of the scroll when triggered. */
- private float mInitialExtentY;
-
- @Override
- public void onFlingStartGesture(int scrollOffsetY, int scrollExtentY) {
- if (!isAllowedToAutoHide() || !cancelCurrentAnimation()) return;
- resetInternalScrollState(scrollOffsetY, scrollExtentY);
- mGestureState = Gesture.FLINGING;
- }
-
- @Override
- public void onFlingEndGesture(int scrollOffsetY, int scrollExtentY) {
- if (mGestureState != Gesture.FLINGING) return;
- mGestureState = Gesture.NONE;
-
- updateTranslation(scrollOffsetY, scrollExtentY);
-
- boolean isScrollingDownward = scrollOffsetY > mLastScrollOffsetY;
-
- boolean isVisibleInitially = mInitialTranslationY < mTotalHeight;
- float percentageVisible = 1.0f - (getTranslationY() / mTotalHeight);
- float visibilityThreshold = isVisibleInitially ? VERTICAL_FLING_HIDE_THRESHOLD
- : VERTICAL_FLING_SHOW_THRESHOLD;
- boolean isVisibleEnough = percentageVisible > visibilityThreshold;
- boolean isNearTopOfPage = scrollOffsetY < (mTotalHeight * FULL_THRESHOLD);
-
- boolean show = (!isScrollingDownward && isVisibleEnough) || isNearTopOfPage;
-
- runUpEventAnimation(show);
- }
-
- @Override
- public void onScrollStarted(int scrollOffsetY, int scrollExtentY) {
- if (!isAllowedToAutoHide() || !cancelCurrentAnimation()) return;
- resetInternalScrollState(scrollOffsetY, scrollExtentY);
- mLastScrollOffsetY = scrollOffsetY;
- mGestureState = Gesture.SCROLLING;
- }
-
- @Override
- public void onScrollEnded(int scrollOffsetY, int scrollExtentY) {
- if (mGestureState != Gesture.SCROLLING) return;
- mGestureState = Gesture.NONE;
-
- updateTranslation(scrollOffsetY, scrollExtentY);
-
- runUpEventAnimation(shouldSnapToVisibleState(scrollOffsetY));
- }
-
- @Override
- public void onScrollOffsetOrExtentChanged(int scrollOffsetY, int scrollExtentY) {
- mLastScrollOffsetY = scrollOffsetY;
-
- if (!shouldConsumeScroll(scrollOffsetY, scrollExtentY)) {
- resetInternalScrollState(scrollOffsetY, scrollExtentY);
- return;
- }
-
- // This function is called for both fling and scrolls.
- if (mGestureState == Gesture.NONE || !cancelCurrentAnimation()
- || isIndependentlyAnimating()) {
- return;
- }
-
- updateTranslation(scrollOffsetY, scrollExtentY);
- }
-
- private void updateTranslation(int scrollOffsetY, int scrollExtentY) {
- float scrollDiff =
- (scrollOffsetY - mInitialOffsetY) + (scrollExtentY - mInitialExtentY);
- float translation =
- MathUtils.clamp(mInitialTranslationY + scrollDiff, mTotalHeight, 0);
-
- // If the container has reached the completely shown position, reset the initial
- // scroll so any movement will start hiding it again.
- if (translation <= 0f) resetInternalScrollState(scrollOffsetY, scrollExtentY);
-
- setTranslationY(translation);
- }
-
- /**
- * Resets the internal values that a scroll or fling will base its calculations off of.
- */
- private void resetInternalScrollState(int scrollOffsetY, int scrollExtentY) {
- mInitialOffsetY = scrollOffsetY;
- mInitialExtentY = scrollExtentY;
- mInitialTranslationY = getTranslationY();
- }
- };
- }
-
- /**
- * @param scrollOffsetY The current scroll offset on the Y axis.
- * @param scrollExtentY The current scroll extent on the Y axis.
- * @return Whether or not the scroll should be consumed by the view.
- */
- protected boolean shouldConsumeScroll(int scrollOffsetY, int scrollExtentY) {
- return true;
- }
-
- /**
- * @param scrollOffsetY The current scroll offset on the Y axis.
- * @return Whether the view should snap to a visible state.
- */
- protected boolean shouldSnapToVisibleState(int scrollOffsetY) {
- boolean isNearTopOfPage = scrollOffsetY < (mTotalHeight * FULL_THRESHOLD);
- boolean isVisibleEnough = getTranslationY() < mTotalHeight * FULL_THRESHOLD;
- return isNearTopOfPage || isVisibleEnough;
- }
-
- /**
- * @return Whether or not the view is animating independent of the user's scroll position.
- */
- protected boolean isIndependentlyAnimating() {
- return false;
- }
-
- /**
- * Creates a listener that is used only to animate the View coming onto the screen.
- * @return The SimpleOnGestureListener that will monitor the View.
- */
- private View.OnLayoutChangeListener createLayoutChangeListener() {
- return new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- removeOnLayoutChangeListener(mLayoutChangeListener);
-
- // Animate the View coming in from the bottom of the screen.
- setTranslationY(mTotalHeight);
- mIsBeingDisplayedForFirstTime = true;
- runUpEventAnimation(true);
- }
- };
- }
-
- /**
- * Create an animation that snaps the View into position vertically.
- * @param visible If true, snaps the View to the bottom-center of the screen. If false,
- * translates the View below the bottom-center of the screen so that it is
- * effectively invisible.
- * @return An animator with the snap animation.
- */
- protected Animator createVerticalSnapAnimation(boolean visible) {
- float targetTranslationY = visible ? 0.0f : mTotalHeight;
- float yDifference = Math.abs(targetTranslationY - getTranslationY()) / mTotalHeight;
- long duration = Math.max(0, (long) (ANIMATION_DURATION_MS * yDifference));
-
- Animator animator = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, targetTranslationY);
- animator.setDuration(duration);
- animator.setInterpolator(mInterpolator);
-
- return animator;
- }
-
- /**
- * Run an animation when a gesture has ended (an 'up' motion event).
- * @param visible Whether or not the view should be visible.
- */
- protected void runUpEventAnimation(boolean visible) {
- if (mCurrentAnimation != null) mCurrentAnimation.cancel();
- mCurrentAnimation = createVerticalSnapAnimation(visible);
- mCurrentAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mGestureState = Gesture.NONE;
- mCurrentAnimation = null;
- mIsBeingDisplayedForFirstTime = false;
- }
- });
- mCurrentAnimation.start();
- }
-
- /**
- * Cancels the current animation, unless the View is coming onto the screen for the first time.
- * @return True if the animation was canceled or wasn't running, false otherwise.
- */
- private boolean cancelCurrentAnimation() {
- if (mIsBeingDisplayedForFirstTime) return false;
- if (mCurrentAnimation != null) mCurrentAnimation.cancel();
- return true;
- }
-
- /**
- * @return Whether the SwipableOverlayView is allowed to hide itself on scroll.
- */
- protected boolean isAllowedToAutoHide() {
- return true;
- }
-
- /**
- * Override gatherTransparentRegion to make this view's layout a placeholder for its
- * animations. This is only called during layout, so it doesn't really make sense to apply
- * post-layout properties like it does by default. Together with setWillNotDraw(false),
- * this ensures no child animation within this view's layout will be clipped by a SurfaceView.
- */
- @Override
- public boolean gatherTransparentRegion(Region region) {
- float translationY = getTranslationY();
- setTranslationY(0);
- boolean result = super.gatherTransparentRegion(region);
- // Restoring TranslationY invalidates this view unnecessarily. However, this function
- // is called as part of layout, which implies a full redraw is about to occur anyway.
- setTranslationY(translationY);
- return result;
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
index 382bfb7c605..b8868d621b2 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
@@ -4,6 +4,7 @@
package org.chromium.weblayer_private;
+import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.os.Build;
@@ -18,6 +19,7 @@ import android.view.ViewStructure;
import android.view.autofill.AutofillValue;
import android.webkit.ValueCallback;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.Callback;
@@ -26,15 +28,18 @@ import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.components.autofill.AutofillActionModeCallback;
import org.chromium.components.autofill.AutofillProvider;
+import org.chromium.components.browser_ui.display_cutout.DisplayCutoutController;
import org.chromium.components.browser_ui.http_auth.LoginPrompt;
import org.chromium.components.browser_ui.media.MediaSessionHelper;
import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate;
import org.chromium.components.browser_ui.util.ComposedBrowserControlsVisibilityDelegate;
+import org.chromium.components.browser_ui.widget.InsetObserverView;
import org.chromium.components.embedder_support.contextmenu.ContextMenuParams;
import org.chromium.components.external_intents.InterceptNavigationDelegateImpl;
import org.chromium.components.find_in_page.FindInPageBridge;
import org.chromium.components.find_in_page.FindMatchRectsDetails;
import org.chromium.components.find_in_page.FindResultBar;
+import org.chromium.components.infobars.InfoBar;
import org.chromium.components.url_formatter.UrlFormatter;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.NavigationHandle;
@@ -51,8 +56,11 @@ import org.chromium.url.GURL;
import org.chromium.weblayer_private.interfaces.APICallException;
import org.chromium.weblayer_private.interfaces.IDownloadCallbackClient;
import org.chromium.weblayer_private.interfaces.IErrorPageCallbackClient;
+import org.chromium.weblayer_private.interfaces.IFaviconFetcher;
+import org.chromium.weblayer_private.interfaces.IFaviconFetcherClient;
import org.chromium.weblayer_private.interfaces.IFindInPageCallbackClient;
import org.chromium.weblayer_private.interfaces.IFullscreenCallbackClient;
+import org.chromium.weblayer_private.interfaces.IGoogleAccountsCallbackClient;
import org.chromium.weblayer_private.interfaces.IMediaCaptureCallbackClient;
import org.chromium.weblayer_private.interfaces.INavigationControllerClient;
import org.chromium.weblayer_private.interfaces.IObjectWrapper;
@@ -65,8 +73,10 @@ import org.chromium.weblayer_private.interfaces.StrictModeWorkaround;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Implementation of ITab.
@@ -86,7 +96,10 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
private ErrorPageCallbackProxy mErrorPageCallbackProxy;
private FullscreenCallbackProxy mFullscreenCallbackProxy;
private TabViewAndroidDelegate mViewAndroidDelegate;
- // BrowserImpl this TabImpl is in. This is only null during creation.
+ private GoogleAccountsCallbackProxy mGoogleAccountsCallbackProxy;
+ // BrowserImpl this TabImpl is in. This is null before attached to a Browser. While this is null
+ // before attached, there are code paths that may trigger calling methods before set.
+ @Nullable
private BrowserImpl mBrowser;
private LoginPrompt mLoginPrompt;
/**
@@ -115,11 +128,14 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
private InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
private InfoBarContainer mInfoBarContainer;
private MediaSessionHelper mMediaSessionHelper;
+ private DisplayCutoutController mDisplayCutoutController;
private boolean mPostContainerViewInitDone;
private WebLayerAccessibilityUtil.Observer mAccessibilityObserver;
+ private Set<FaviconCallbackProxy> mFaviconCallbackProxies = new HashSet<>();
+
private static class InternalAccessDelegateImpl
implements ViewEventSink.InternalAccessDelegate {
@Override
@@ -240,6 +256,11 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
hideFindInPageUiAndNotifyClient();
}
}
+ @Override
+ public void viewportFitChanged(@WebContentsObserver.ViewportFitType int value) {
+ ensureDisplayCutoutController();
+ mDisplayCutoutController.setViewportFit(value);
+ }
};
mWebContents.addObserver(mWebContentsObserver);
@@ -253,7 +274,8 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
mBrowserControlsDelegates.add(delegate);
mBrowserControlsVisibility.addDelegate(delegate);
}
- mConstraintsUpdatedCallback = (constraints) -> onBrowserControlsStateUpdated(constraints);
+ mConstraintsUpdatedCallback =
+ (constraint) -> onBrowserControlsConstraintUpdated(constraint);
mBrowserControlsVisibility.addObserver(mConstraintsUpdatedCallback);
mInterceptNavigationDelegateClient = new InterceptNavigationDelegateClientImpl(this);
@@ -309,7 +331,7 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
mWebContents.setTopLevelNativeWindow(mBrowser.getWindowAndroid());
mViewAndroidDelegate.setContainerView(mBrowser.getViewAndroidDelegateContainerView());
doInitAfterSettingContainerView();
- updateWebContentsVisibility();
+ updateViewAttachedStateFromBrowser();
boolean attached = (mBrowser.getContext() != null);
mInterceptNavigationDelegateClient.onActivityAttachmentChanged(attached);
@@ -341,6 +363,11 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
}
}
+ public void updateViewAttachedStateFromBrowser() {
+ updateWebContentsVisibility();
+ updateDisplayCutoutController();
+ }
+
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
if (mAutofillProvider == null) return;
mAutofillProvider.onProvideAutoFillVirtualStructure(structure, flags);
@@ -383,6 +410,7 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
mNativeTab, topControlsContainerViewHandle, bottomControlsContainerViewHandle);
mInfoBarContainer.onTabDidGainActive();
updateWebContentsVisibility();
+ updateDisplayCutoutController();
}
/**
@@ -393,8 +421,11 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
mAutofillProvider.hidePopup();
}
+ if (mFullscreenCallbackProxy != null) mFullscreenCallbackProxy.destroyToast();
+
hideFindInPageUiAndNotifyClient();
updateWebContentsVisibility();
+ updateDisplayCutoutController();
// This method is called as part of the final phase of TabImpl destruction, at which
// point mInfoBarContainer has already been destroyed.
@@ -409,8 +440,13 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
* Returns whether this Tab is visible.
*/
public boolean isVisible() {
- return (mBrowser.getActiveTab() == this
- && (mBrowser.isStarted() || mBrowser.isFragmentStoppedForConfigurationChange()));
+ return isActiveTab()
+ && ((mBrowser.isStarted() && mBrowser.isViewAttachedToWindow())
+ || mBrowser.isFragmentStoppedForConfigurationChange());
+ }
+
+ private boolean isActiveTab() {
+ return mBrowser != null && mBrowser.getActiveTab() == this;
}
private void updateWebContentsVisibility() {
@@ -423,6 +459,13 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
}
}
+ private void updateDisplayCutoutController() {
+ if (mDisplayCutoutController == null) return;
+
+ mDisplayCutoutController.onActivityAttachmentChanged(mBrowser.getWindowAndroid());
+ mDisplayCutoutController.maybeUpdateLayout();
+ }
+
public void loadUrl(LoadUrlParams loadUrlParams) {
String url = loadUrlParams.getUrl();
if (url == null || url.isEmpty()) return;
@@ -491,7 +534,7 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
StrictModeWorkaround.apply();
if (client != null) {
if (mFullscreenCallbackProxy == null) {
- mFullscreenCallbackProxy = new FullscreenCallbackProxy(mNativeTab, client);
+ mFullscreenCallbackProxy = new FullscreenCallbackProxy(this, mNativeTab, client);
} else {
mFullscreenCallbackProxy.setClient(client);
}
@@ -502,6 +545,38 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
}
@Override
+ public void setGoogleAccountsCallbackClient(IGoogleAccountsCallbackClient client) {
+ StrictModeWorkaround.apply();
+ if (client != null) {
+ if (mGoogleAccountsCallbackProxy == null) {
+ mGoogleAccountsCallbackProxy = new GoogleAccountsCallbackProxy(mNativeTab, client);
+ } else {
+ mGoogleAccountsCallbackProxy.setClient(client);
+ }
+ } else if (mGoogleAccountsCallbackProxy != null) {
+ mGoogleAccountsCallbackProxy.destroy();
+ mGoogleAccountsCallbackProxy = null;
+ }
+ }
+
+ @Override
+ public IFaviconFetcher createFaviconFetcher(IFaviconFetcherClient client) {
+ StrictModeWorkaround.apply();
+ FaviconCallbackProxy proxy = new FaviconCallbackProxy(this, mNativeTab, client);
+ mFaviconCallbackProxies.add(proxy);
+ return proxy;
+ }
+
+ @Override
+ public void setTranslateTargetLanguage(String targetLanguage) {
+ TabImplJni.get().setTranslateTargetLanguage(mNativeTab, targetLanguage);
+ }
+
+ public void removeFaviconCallbackProxy(FaviconCallbackProxy proxy) {
+ mFaviconCallbackProxies.remove(proxy);
+ }
+
+ @Override
public void executeScript(String script, boolean useSeparateIsolate, IObjectWrapper callback) {
StrictModeWorkaround.apply();
Callback<String> nativeCallback = new Callback<String>() {
@@ -798,6 +873,11 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
}
}
+ if (mDisplayCutoutController != null) {
+ mDisplayCutoutController.destroy();
+ mDisplayCutoutController = null;
+ }
+
if (mTabCallbackProxy != null) {
mTabCallbackProxy.destroy();
mTabCallbackProxy = null;
@@ -814,8 +894,13 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
mNewTabCallbackProxy.destroy();
mNewTabCallbackProxy = null;
}
+ if (mGoogleAccountsCallbackProxy != null) {
+ mGoogleAccountsCallbackProxy.destroy();
+ mGoogleAccountsCallbackProxy = null;
+ }
mInterceptNavigationDelegateClient.destroy();
+ mInterceptNavigationDelegateClient = null;
mInterceptNavigationDelegate = null;
mInfoBarContainer.destroy();
@@ -824,6 +909,15 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
mMediaStreamManager.destroy();
mMediaStreamManager = null;
+ // Destroying FaviconCallbackProxy removes from mFaviconCallbackProxies. Copy to avoid
+ // problems.
+ Set<FaviconCallbackProxy> faviconCallbackProxies = mFaviconCallbackProxies;
+ mFaviconCallbackProxies = new HashSet<>();
+ for (FaviconCallbackProxy proxy : faviconCallbackProxies) {
+ proxy.destroy();
+ }
+ assert mFaviconCallbackProxies.isEmpty();
+
sTabMap.remove(mId);
// ObservableSupplierImpl.addObserver() posts a task to notify the observer, ensure the
@@ -852,6 +946,12 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
mBrowserControlsDelegates.get(reason).set(constraint);
}
+ @BrowserControlsState
+ /* package */ int getBrowserControlsVisibilityConstraint(
+ @ImplControlsVisibilityReason int reason) {
+ return mBrowserControlsDelegates.get(reason).get();
+ }
+
@CalledByNative
public void showRepostFormWarningDialog() {
BrowserViewController viewController = getViewController();
@@ -884,7 +984,7 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
if (mBrowser.getActiveTab() != this) return;
- onBrowserControlsStateUpdated(mBrowserControlsVisibility.get());
+ onBrowserControlsConstraintUpdated(mBrowserControlsVisibility.get());
}
@VisibleForTesting
@@ -892,40 +992,86 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
return mBrowserControlsVisibility.get() == BrowserControlsState.BOTH;
}
- private void onBrowserControlsStateUpdated(int state) {
+ @VisibleForTesting
+ public boolean didShowFullscreenToast() {
+ return mFullscreenCallbackProxy != null
+ && mFullscreenCallbackProxy.didShowFullscreenToast();
+ }
+
+ private void onBrowserControlsConstraintUpdated(int constraint) {
+ // WARNING: this may be called before attached. This means |mBrowser| may be null.
+
// If something has overridden the FIP's SHOWN constraint, cancel FIP. This causes FIP to
// dismiss when entering fullscreen.
- if (state != BrowserControlsState.SHOWN) {
+ if (constraint != BrowserControlsState.SHOWN) {
hideFindInPageUiAndNotifyClient();
}
- // Don't animate when hiding the controls.
- boolean animate = state != BrowserControlsState.HIDDEN;
+ BrowserViewController viewController = getViewController();
+ // Don't animate when hiding the controls unless an animation was requested by
+ // BrowserControlsContainerView.
+ boolean animate = constraint != BrowserControlsState.HIDDEN
+ || (viewController != null
+ && viewController.shouldAnimateBrowserControlsHeightChanges());
- // If the renderer is not controlling the offsets (possiblye hung or crashed). Then this
+ // If the renderer is not controlling the offsets (possibly hung or crashed). Then this
// needs to force the controls to show (because notification from the renderer will not
// happen). For js dialogs, the renderer's update will come when the dialog is hidden, and
// since that animates from 0 height, it causes a flicker since the override is already set
// to fully show. Thus, disable animation.
- if (state == BrowserControlsState.SHOWN && mBrowser != null
- && mBrowser.getActiveTab() == this
+ if (constraint == BrowserControlsState.SHOWN && isActiveTab()
&& !TabImplJni.get().isRendererControllingBrowserControlsOffsets(mNativeTab)) {
mViewAndroidDelegate.setIgnoreRendererUpdates(true);
- getViewController().showControls();
+ if (viewController != null) viewController.showControls();
animate = false;
} else {
mViewAndroidDelegate.setIgnoreRendererUpdates(false);
}
- TabImplJni.get().updateBrowserControlsState(mNativeTab, state, animate);
+ TabImplJni.get().updateBrowserControlsConstraint(mNativeTab, constraint, animate);
+ }
+
+ private void ensureDisplayCutoutController() {
+ if (mDisplayCutoutController != null) return;
+
+ mDisplayCutoutController =
+ new DisplayCutoutController(new DisplayCutoutController.Delegate() {
+ @Override
+ public Activity getAttachedActivity() {
+ WindowAndroid window = mBrowser.getWindowAndroid();
+ return window == null ? null : window.getActivity().get();
+ }
+
+ @Override
+ public WebContents getWebContents() {
+ return mWebContents;
+ }
+
+ @Override
+ public InsetObserverView getInsetObserverView() {
+ return mBrowser.getViewController().getInsetObserverView();
+ }
+
+ @Override
+ public boolean isInteractable() {
+ return isVisible();
+ }
+ });
}
/**
* Returns the BrowserViewController for this TabImpl, but only if this
- * is the active TabImpl.
+ * is the active TabImpl. Can also return null if in the middle of shutdown
+ * or Browser is not attached to any activity.
*/
+ @Nullable
private BrowserViewController getViewController() {
- return (mBrowser.getActiveTab() == this) ? mBrowser.getViewController() : null;
+ if (!isActiveTab()) return null;
+ // During rotation it's possible for this to be called before BrowserViewController has been
+ // updated. Verify BrowserViewController reflects this is the active tab before returning
+ // it.
+ BrowserViewController viewController = mBrowser.getPossiblyNullViewController();
+ return viewController != null && viewController.getTab() == this ? viewController : null;
}
@VisibleForTesting
@@ -933,6 +1079,16 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
return mInfoBarContainer.getContainerViewForTesting().isAllowedToAutoHide();
}
+ @VisibleForTesting
+ public String getTranslateInfoBarTargetLanguageForTesting() {
+ if (!mInfoBarContainer.hasInfoBars()) return null;
+
+ ArrayList<InfoBar> infobars = mInfoBarContainer.getInfoBarsForTesting();
+ TranslateCompactInfoBar translateInfoBar = (TranslateCompactInfoBar) infobars.get(0);
+
+ return translateInfoBar.getTargetLanguageForTesting();
+ }
+
@NativeMethods
interface Natives {
TabImpl fromWebContents(WebContents webContents);
@@ -946,7 +1102,8 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
WebContents getWebContents(long nativeTabImpl);
void executeScript(long nativeTabImpl, String script, boolean useSeparateIsolate,
Callback<String> callback);
- void updateBrowserControlsState(long nativeTabImpl, int newConstraint, boolean animate);
+ void updateBrowserControlsConstraint(
+ long nativeTabImpl, int newConstraint, boolean animate);
String getGuid(long nativeTabImpl);
void captureScreenShot(long nativeTabImpl, float scale,
ValueCallback<Pair<Bitmap, Integer>> valueCallback);
@@ -960,5 +1117,6 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
void unregisterWebMessageCallback(long nativeTabImpl, String jsObjectName);
boolean canTranslate(long nativeTabImpl);
void showTranslateUi(long nativeTabImpl);
+ void setTranslateTargetLanguage(long nativeTabImpl, String targetLanguage);
}
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java
index a97315e6fa4..9e7ca44dd30 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java
@@ -20,6 +20,14 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.infobar.ActionType;
+import org.chromium.components.infobars.InfoBar;
+import org.chromium.components.infobars.InfoBarCompactLayout;
+import org.chromium.components.translate.TranslateMenu;
+import org.chromium.components.translate.TranslateMenuHelper;
+import org.chromium.components.translate.TranslateOption;
+import org.chromium.components.translate.TranslateOptions;
+import org.chromium.components.translate.TranslateTabLayout;
import org.chromium.ui.widget.Toast;
/**
@@ -463,6 +471,13 @@ public class TranslateCompactInfoBar extends InfoBar
return this.isTabSelectedForTesting(TARGET_TAB_INDEX);
}
+ /**
+ * Returns the name of the target language. This is only used for automation testing.
+ */
+ public String getTargetLanguageForTesting() {
+ return mOptions.targetLanguageName();
+ }
+
private void createAndShowSnackbar(int actionId) {
// NOTE: WebLayer doesn't have snackbars, so the relevant action is just taken directly.
// TODO(blundell): If WebLayer ends up staying with this implementation long-term, update
@@ -541,9 +556,8 @@ public class TranslateCompactInfoBar extends InfoBar
return mParent != null ? mParent.getWidth() : 0;
}
- @CalledByNative
// Selects the tab corresponding to |actionType| to simulate the user pressing on this tab.
- private void selectTabForTesting(int actionType) {
+ void selectTabForTesting(int actionType) {
if (actionType == ActionType.TRANSLATE) {
mTabLayout.getTabAt(TARGET_TAB_INDEX).select();
} else if (actionType == ActionType.TRANSLATE_SHOW_ORIGINAL) {
@@ -553,18 +567,6 @@ public class TranslateCompactInfoBar extends InfoBar
}
}
- @CalledByNative
- // Simulates a click of the overflow menu item for "never translate this language."
- private void clickNeverTranslateLanguageMenuItemForTesting() {
- onOverflowMenuItemClicked(TranslateMenu.ID_OVERFLOW_NEVER_LANGUAGE);
- }
-
- @CalledByNative
- // Simulates a click of the overflow menu item for "never translate this site."
- private void clickNeverTranslateSiteMenuItemForTesting() {
- onOverflowMenuItemClicked(TranslateMenu.ID_OVERFLOW_NEVER_SITE);
- }
-
@NativeMethods
interface Natives {
void applyStringTranslateOption(long nativeTranslateCompactInfoBar,
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateMenu.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateMenu.java
deleted file mode 100644
index cfb1a06c2f5..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateMenu.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Translate menu config and its item entity definition.
- */
-public final class TranslateMenu {
- /**
- * The menu item entity.
- */
- static final class MenuItem {
- public final int mType;
- public final int mId;
- public final String mCode;
- public final boolean mWithDivider;
-
- MenuItem(int itemType, int itemId, boolean withDivider) {
- this(itemType, itemId, EMPTY_STRING, withDivider);
- }
-
- MenuItem(int itemType, int itemId, String code) {
- this(itemType, itemId, code, false);
- }
-
- MenuItem(int itemType, int itemId, String code, boolean withDivider) {
- mType = itemType;
- mId = itemId;
- mCode = code;
- mWithDivider = withDivider;
- }
- }
-
- public static final String EMPTY_STRING = "";
-
- // Menu type config.
- public static final int MENU_OVERFLOW = 0;
- public static final int MENU_TARGET_LANGUAGE = 1;
- public static final int MENU_SOURCE_LANGUAGE = 2;
-
- // Menu item type config.
- public static final int ITEM_LANGUAGE = 0;
- public static final int ITEM_CHECKBOX_OPTION = 1;
- public static final int MENU_ITEM_TYPE_COUNT = 2;
-
- // Menu Item ID config for MENU_OVERFLOW.
- public static final int ID_OVERFLOW_MORE_LANGUAGE = 0;
- public static final int ID_OVERFLOW_ALWAYS_TRANSLATE = 1;
- public static final int ID_OVERFLOW_NEVER_SITE = 2;
- public static final int ID_OVERFLOW_NEVER_LANGUAGE = 3;
- public static final int ID_OVERFLOW_NOT_THIS_LANGUAGE = 4;
-
- /**
- * Build overflow menu item list.
- */
- static List<MenuItem> getOverflowMenu(boolean isIncognito) {
- List<MenuItem> menu = new ArrayList<MenuItem>();
- menu.add(new MenuItem(ITEM_CHECKBOX_OPTION, ID_OVERFLOW_MORE_LANGUAGE, true));
- if (!isIncognito) {
- // "Always translate" does nothing in incognito mode, so just hide it.
- menu.add(new MenuItem(ITEM_CHECKBOX_OPTION, ID_OVERFLOW_ALWAYS_TRANSLATE, false));
- }
- menu.add(new MenuItem(ITEM_CHECKBOX_OPTION, ID_OVERFLOW_NEVER_LANGUAGE, false));
- menu.add(new MenuItem(ITEM_CHECKBOX_OPTION, ID_OVERFLOW_NEVER_SITE, false));
- menu.add(new MenuItem(ITEM_CHECKBOX_OPTION, ID_OVERFLOW_NOT_THIS_LANGUAGE, false));
- return menu;
- }
-
- private TranslateMenu() {}
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateMenuHelper.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateMenuHelper.java
deleted file mode 100644
index 16454817172..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateMenuHelper.java
+++ /dev/null
@@ -1,321 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Build;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListPopupWindow;
-import android.widget.PopupWindow;
-import android.widget.TextView;
-
-import androidx.core.content.ContextCompat;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A Helper class for managing the Translate Overflow Menu.
- */
-public class TranslateMenuHelper implements AdapterView.OnItemClickListener {
- private final TranslateMenuListener mMenuListener;
- private final TranslateOptions mOptions;
-
- private ContextThemeWrapper mContextWrapper;
- private TranslateMenuAdapter mAdapter;
- private View mAnchorView;
- private ListPopupWindow mPopup;
- private boolean mIsIncognito;
-
- /**
- * Interface for receiving the click event of menu item.
- */
- public interface TranslateMenuListener {
- void onOverflowMenuItemClicked(int itemId);
- void onTargetMenuItemClicked(String code);
- void onSourceMenuItemClicked(String code);
- }
-
- public TranslateMenuHelper(Context context, View anchorView, TranslateOptions options,
- TranslateMenuListener itemListener, boolean isIncognito) {
- mContextWrapper = new ContextThemeWrapper(context, R.style.OverflowMenuThemeOverlay);
- mAnchorView = anchorView;
- mOptions = options;
- mMenuListener = itemListener;
- mIsIncognito = isIncognito;
- }
-
- /**
- * Build translate menu by menu type.
- */
- private List<TranslateMenu.MenuItem> getMenuList(int menuType) {
- List<TranslateMenu.MenuItem> menuList = new ArrayList<TranslateMenu.MenuItem>();
- if (menuType == TranslateMenu.MENU_OVERFLOW) {
- // TODO(googleo): Add language short list above static menu after its data is ready.
- menuList.addAll(TranslateMenu.getOverflowMenu(mIsIncognito));
- } else {
- for (int i = 0; i < mOptions.allLanguages().size(); ++i) {
- String code = mOptions.allLanguages().get(i).mLanguageCode;
- // Avoid source language in the source language list.
- if (menuType == TranslateMenu.MENU_SOURCE_LANGUAGE
- && code.equals(mOptions.sourceLanguageCode())) {
- continue;
- }
- // Avoid target language in the target language list.
- if (menuType == TranslateMenu.MENU_TARGET_LANGUAGE
- && code.equals(mOptions.targetLanguageCode())) {
- continue;
- }
- menuList.add(new TranslateMenu.MenuItem(TranslateMenu.ITEM_LANGUAGE, i, code));
- }
- }
- return menuList;
- }
-
- /**
- * Show the overflow menu.
- * @param menuType The type of overflow menu to show.
- * @param maxwidth Maximum width of menu. Set to 0 when not specified.
- */
- public void show(int menuType, int maxWidth) {
- if (mPopup == null) {
- mPopup = new ListPopupWindow(mContextWrapper, null, android.R.attr.popupMenuStyle);
- mPopup.setModal(true);
- mPopup.setAnchorView(mAnchorView);
- mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
-
- // Need to explicitly set the background here. Relying on it being set in the style
- // caused an incorrectly drawn background.
- // TODO(martiw): We might need a new menu background here.
- mPopup.setBackgroundDrawable(
- ContextCompat.getDrawable(mContextWrapper, R.drawable.popup_bg_tinted));
-
- mPopup.setOnItemClickListener(this);
-
- // The menu must be shifted down by the height of the anchor view in order to be
- // displayed over and above it.
- int anchorHeight = mAnchorView.getHeight();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- // Setting a positive offset here shifts the menu down.
- mPopup.setVerticalOffset(anchorHeight);
- } else {
- // The framework's PopupWindow positioning changed between N and M. Setting
- // a negative offset here shifts the menu down rather than up.
- mPopup.setVerticalOffset(-anchorHeight);
- }
-
- mAdapter = new TranslateMenuAdapter(menuType);
- mPopup.setAdapter(mAdapter);
- } else {
- mAdapter.refreshMenu(menuType);
- }
-
- if (menuType == TranslateMenu.MENU_OVERFLOW) {
- // Use measured width when it is a overflow menu.
- Rect bgPadding = new Rect();
- mPopup.getBackground().getPadding(bgPadding);
- int measuredWidth = measureMenuWidth(mAdapter) + bgPadding.left + bgPadding.right;
- mPopup.setWidth((maxWidth > 0 && measuredWidth > maxWidth) ? maxWidth : measuredWidth);
- } else {
- // Use fixed width otherwise.
- int popupWidth = mContextWrapper.getResources().getDimensionPixelSize(
- R.dimen.weblayer_infobar_translate_menu_width);
- mPopup.setWidth(popupWidth);
- }
-
- // When layout is RTL, set the horizontal offset to align the menu with the left side of the
- // screen.
- if (mAnchorView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
- int[] tempLocation = new int[2];
- mAnchorView.getLocationOnScreen(tempLocation);
- mPopup.setHorizontalOffset(-tempLocation[0]);
- }
-
- if (!mPopup.isShowing()) {
- mPopup.show();
- mPopup.getListView().setItemsCanFocus(true);
- }
- }
-
- private int measureMenuWidth(TranslateMenuAdapter adapter) {
- final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-
- final int count = adapter.getCount();
- int width = 0;
- int itemType = 0;
- View itemView = null;
- for (int i = 0; i < count; i++) {
- final int positionType = adapter.getItemViewType(i);
- if (positionType != itemType) {
- itemType = positionType;
- itemView = null;
- }
- itemView = adapter.getView(i, itemView, null);
- itemView.measure(widthMeasureSpec, heightMeasureSpec);
- width = Math.max(width, itemView.getMeasuredWidth());
- }
- return width;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- dismiss();
-
- TranslateMenu.MenuItem item = mAdapter.getItem(position);
- switch (mAdapter.mMenuType) {
- case TranslateMenu.MENU_OVERFLOW:
- mMenuListener.onOverflowMenuItemClicked(item.mId);
- return;
- case TranslateMenu.MENU_TARGET_LANGUAGE:
- mMenuListener.onTargetMenuItemClicked(item.mCode);
- return;
- case TranslateMenu.MENU_SOURCE_LANGUAGE:
- mMenuListener.onSourceMenuItemClicked(item.mCode);
- return;
- default:
- assert false : "Unsupported Menu Item Id";
- }
- }
-
- /**
- * Dismisses the translate option menu.
- */
- public void dismiss() {
- if (isShowing()) {
- mPopup.dismiss();
- }
- }
-
- /**
- * @return Whether the menu is currently showing.
- */
- public boolean isShowing() {
- if (mPopup == null) {
- return false;
- }
- return mPopup.isShowing();
- }
-
- /**
- * The provides the views of the menu items and dividers.
- */
- private final class TranslateMenuAdapter extends ArrayAdapter<TranslateMenu.MenuItem> {
- private final LayoutInflater mInflater;
- private int mMenuType;
-
- public TranslateMenuAdapter(int menuType) {
- super(mContextWrapper, R.layout.weblayer_translate_menu_item, getMenuList(menuType));
- mInflater = LayoutInflater.from(mContextWrapper);
- mMenuType = menuType;
- }
-
- private void refreshMenu(int menuType) {
- // MENU_OVERFLOW is static and it should not reload.
- if (menuType == TranslateMenu.MENU_OVERFLOW) return;
-
- clear();
-
- mMenuType = menuType;
- addAll(getMenuList(menuType));
- notifyDataSetChanged();
- }
-
- private String getItemViewText(TranslateMenu.MenuItem item) {
- if (mMenuType == TranslateMenu.MENU_OVERFLOW) {
- // Overflow menu items are manually defined one by one.
- String source = mOptions.sourceLanguageName();
- switch (item.mId) {
- case TranslateMenu.ID_OVERFLOW_ALWAYS_TRANSLATE:
- return mContextWrapper.getString(
- R.string.translate_option_always_translate, source);
- case TranslateMenu.ID_OVERFLOW_MORE_LANGUAGE:
- return mContextWrapper.getString(R.string.translate_option_more_language);
- case TranslateMenu.ID_OVERFLOW_NEVER_SITE:
- return mContextWrapper.getString(R.string.translate_never_translate_site);
- case TranslateMenu.ID_OVERFLOW_NEVER_LANGUAGE:
- return mContextWrapper.getString(
- R.string.translate_option_never_translate, source);
- case TranslateMenu.ID_OVERFLOW_NOT_THIS_LANGUAGE:
- return mContextWrapper.getString(
- R.string.translate_option_not_source_language, source);
- default:
- assert false : "Unexpected Overflow Item Id";
- }
- } else {
- // Get source and target language menu items text by language code.
- return mOptions.getRepresentationFromCode(item.mCode);
- }
- return "";
- }
-
- @Override
- public int getItemViewType(int position) {
- return getItem(position).mType;
- }
-
- @Override
- public int getViewTypeCount() {
- return TranslateMenu.MENU_ITEM_TYPE_COUNT;
- }
-
- private View getItemView(
- View menuItemView, int position, ViewGroup parent, int resourceId) {
- if (menuItemView == null) {
- menuItemView = mInflater.inflate(resourceId, parent, false);
- }
- ((TextView) menuItemView.findViewById(R.id.weblayer_menu_item_text))
- .setText(getItemViewText(getItem(position)));
- return menuItemView;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View menuItemView = convertView;
- switch (getItemViewType(position)) {
- case TranslateMenu.ITEM_CHECKBOX_OPTION:
- menuItemView = getItemView(menuItemView, position, parent,
- R.layout.weblayer_translate_menu_item_checked);
-
- ImageView checkboxIcon =
- menuItemView.findViewById(R.id.weblayer_menu_item_icon);
- if (getItem(position).mId == TranslateMenu.ID_OVERFLOW_ALWAYS_TRANSLATE
- && mOptions.getTranslateState(TranslateOptions.Type.ALWAYS_LANGUAGE)) {
- checkboxIcon.setVisibility(View.VISIBLE);
- } else if (getItem(position).mId == TranslateMenu.ID_OVERFLOW_NEVER_LANGUAGE
- && mOptions.getTranslateState(TranslateOptions.Type.NEVER_LANGUAGE)) {
- checkboxIcon.setVisibility(View.VISIBLE);
- } else if (getItem(position).mId == TranslateMenu.ID_OVERFLOW_NEVER_SITE
- && mOptions.getTranslateState(TranslateOptions.Type.NEVER_DOMAIN)) {
- checkboxIcon.setVisibility(View.VISIBLE);
- } else {
- checkboxIcon.setVisibility(View.INVISIBLE);
- }
-
- View divider =
- (View) menuItemView.findViewById(R.id.weblayer_menu_item_divider);
- if (getItem(position).mWithDivider) {
- divider.setVisibility(View.VISIBLE);
- }
- break;
- case TranslateMenu.ITEM_LANGUAGE:
- menuItemView = getItemView(
- menuItemView, position, parent, R.layout.weblayer_translate_menu_item);
- break;
- default:
- assert false : "Unexpected MenuItem type";
- }
- return menuItemView;
- }
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateOptions.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateOptions.java
deleted file mode 100644
index ba38d4e26f6..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateOptions.java
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.text.TextUtils;
-
-import androidx.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A class that keeps the state of the different translation options and
- * languages.
- */
-public class TranslateOptions {
- /**
- * A container for Language Code and it's translated representation and it's native UMA
- * specific hashcode.
- * For example for Spanish when viewed from a French locale, this will contain es, Espagnol,
- * 114573335
- **/
- public static class TranslateLanguageData {
- public final String mLanguageCode;
- public final String mLanguageRepresentation;
- public final Integer mLanguageUMAHashCode;
-
- public TranslateLanguageData(
- String languageCode, String languageRepresentation, Integer uMAhashCode) {
- assert languageCode != null;
- assert languageRepresentation != null;
- mLanguageCode = languageCode;
- mLanguageRepresentation = languageRepresentation;
- mLanguageUMAHashCode = uMAhashCode;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof TranslateLanguageData)) return false;
- TranslateLanguageData other = (TranslateLanguageData) obj;
- return this.mLanguageCode.equals(other.mLanguageCode)
- && this.mLanguageRepresentation.equals(other.mLanguageRepresentation)
- && this.mLanguageUMAHashCode.equals(other.mLanguageUMAHashCode);
- }
-
- @Override
- public int hashCode() {
- return (mLanguageCode + mLanguageRepresentation).hashCode();
- }
-
- @Override
- public String toString() {
- return "mLanguageCode:" + mLanguageCode + " - mlanguageRepresentation "
- + mLanguageRepresentation + " - mLanguageUMAHashCode " + mLanguageUMAHashCode;
- }
- }
-
- // Values must be numerated from 0 and can't have gaps
- // (they're used for indexing mOptions).
- @IntDef({Type.NEVER_LANGUAGE, Type.NEVER_DOMAIN, Type.ALWAYS_LANGUAGE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {
- int NEVER_LANGUAGE = 0;
- int NEVER_DOMAIN = 1;
- int ALWAYS_LANGUAGE = 2;
-
- int NUM_ENTRIES = 3;
- }
-
- private String mSourceLanguageCode;
- private String mTargetLanguageCode;
-
- private final ArrayList<TranslateLanguageData> mAllLanguages;
-
- // language code to translated language name map
- // Conceptually final
- private Map<String, String> mCodeToRepresentation;
-
- // Language code to its UMA hashcode representation.
- private Map<String, Integer> mCodeToUMAHashCode;
-
- // Will reflect the state before the object was ever modified
- private final boolean[] mOriginalOptions;
-
- private final String mOriginalSourceLanguageCode;
- private final String mOriginalTargetLanguageCode;
- private final boolean mTriggeredFromMenu;
-
- private final boolean[] mOptions;
-
- private TranslateOptions(String sourceLanguageCode, String targetLanguageCode,
- ArrayList<TranslateLanguageData> allLanguages, boolean neverLanguage,
- boolean neverDomain, boolean alwaysLanguage, boolean triggeredFromMenu,
- boolean[] originalOptions) {
- assert Type.NUM_ENTRIES == 3;
- mOptions = new boolean[Type.NUM_ENTRIES];
- mOptions[Type.NEVER_LANGUAGE] = neverLanguage;
- mOptions[Type.NEVER_DOMAIN] = neverDomain;
- mOptions[Type.ALWAYS_LANGUAGE] = alwaysLanguage;
-
- mOriginalOptions = originalOptions == null ? mOptions.clone() : originalOptions.clone();
-
- mSourceLanguageCode = sourceLanguageCode;
- mTargetLanguageCode = targetLanguageCode;
- mOriginalSourceLanguageCode = mSourceLanguageCode;
- mOriginalTargetLanguageCode = mTargetLanguageCode;
- mTriggeredFromMenu = triggeredFromMenu;
-
- mAllLanguages = allLanguages;
- mCodeToRepresentation = new HashMap<String, String>();
- mCodeToUMAHashCode = new HashMap<String, Integer>();
- for (TranslateLanguageData language : allLanguages) {
- mCodeToRepresentation.put(language.mLanguageCode, language.mLanguageRepresentation);
- mCodeToUMAHashCode.put(language.mLanguageCode, language.mLanguageUMAHashCode);
- }
- }
-
- /**
- * Creates a TranslateOptions by the given data.
- */
- public static TranslateOptions create(String sourceLanguageCode, String targetLanguageCode,
- String[] languages, String[] codes, boolean alwaysTranslate, boolean triggeredFromMenu,
- int[] hashCodes) {
- assert languages.length == codes.length;
-
- ArrayList<TranslateLanguageData> languageList = new ArrayList<TranslateLanguageData>();
- for (int i = 0; i < languages.length; ++i) {
- Integer hashCode = hashCodes != null ? Integer.valueOf(hashCodes[i]) : null;
- languageList.add(new TranslateLanguageData(codes[i], languages[i], hashCode));
- }
- return new TranslateOptions(sourceLanguageCode, targetLanguageCode, languageList, false,
- false, alwaysTranslate, triggeredFromMenu, null);
- }
-
- /**
- * Returns a copy of the current instance.
- */
- TranslateOptions copy() {
- return new TranslateOptions(mSourceLanguageCode, mTargetLanguageCode, mAllLanguages,
- mOptions[Type.NEVER_LANGUAGE], mOptions[Type.NEVER_DOMAIN],
- mOptions[Type.ALWAYS_LANGUAGE], mTriggeredFromMenu, mOriginalOptions);
- }
-
- public String sourceLanguageName() {
- return getRepresentationFromCode(mSourceLanguageCode);
- }
-
- public String targetLanguageName() {
- return getRepresentationFromCode(mTargetLanguageCode);
- }
-
- public String sourceLanguageCode() {
- return mSourceLanguageCode;
- }
-
- public String targetLanguageCode() {
- return mTargetLanguageCode;
- }
-
- public boolean triggeredFromMenu() {
- return mTriggeredFromMenu;
- }
-
- public boolean optionsChanged() {
- return (!mSourceLanguageCode.equals(mOriginalSourceLanguageCode))
- || (!mTargetLanguageCode.equals(mOriginalTargetLanguageCode))
- || (mOptions[Type.NEVER_LANGUAGE] != mOriginalOptions[Type.NEVER_LANGUAGE])
- || (mOptions[Type.NEVER_DOMAIN] != mOriginalOptions[Type.NEVER_DOMAIN])
- || (mOptions[Type.ALWAYS_LANGUAGE] != mOriginalOptions[Type.ALWAYS_LANGUAGE]);
- }
-
- public List<TranslateLanguageData> allLanguages() {
- return mAllLanguages;
- }
-
- public boolean getTranslateState(@Type int type) {
- return mOptions[type];
- }
-
- public boolean setSourceLanguage(String languageCode) {
- boolean canSet = canSetLanguage(languageCode, mTargetLanguageCode);
- if (canSet) mSourceLanguageCode = languageCode;
- return canSet;
- }
-
- public boolean setTargetLanguage(String languageCode) {
- boolean canSet = canSetLanguage(mSourceLanguageCode, languageCode);
- if (canSet) mTargetLanguageCode = languageCode;
- return canSet;
- }
-
- /**
- * Sets the new state of never translate domain.
- *
- * @return true if the toggling was possible
- */
- public void toggleNeverTranslateDomainState(boolean value) {
- mOptions[Type.NEVER_DOMAIN] = value;
- }
-
- /**
- * Sets the new state of never translate language.
- *
- * @return true if the toggling was possible
- */
- public boolean toggleNeverTranslateLanguageState(boolean value) {
- // Do not toggle if we are activating NeverLanguage but AlwaysTranslate
- // for a language pair with the same source language is already active.
- if (mOptions[Type.ALWAYS_LANGUAGE] && value) return false;
- mOptions[Type.NEVER_LANGUAGE] = value;
- return true;
- }
-
- /**
- * Sets the new state of never translate a language pair.
- *
- * @return true if the toggling was possible
- */
- public boolean toggleAlwaysTranslateLanguageState(boolean value) {
- // Do not toggle if we are activating AlwaysLanguage but NeverLanguage is active already.
- if (mOptions[Type.NEVER_LANGUAGE] && value) return false;
- mOptions[Type.ALWAYS_LANGUAGE] = value;
- return true;
- }
-
- /**
- * Gets the language's translated representation from a given language code.
- * @param languageCode ISO code for the language
- * @return The translated representation of the language, or "" if not found.
- */
- public String getRepresentationFromCode(String languageCode) {
- return isValidLanguageCode(languageCode) ? mCodeToRepresentation.get(languageCode) : "";
- }
-
- /**
- * Gets the language's UMA hashcode representation from a given language code.
- * @param languageCode ISO code for the language
- * @return The UMA hashcode representation of the language, or null if not found.
- */
- public Integer getUMAHashCodeFromCode(String languageCode) {
- return isValidLanguageUMAHashCode(languageCode) ? mCodeToUMAHashCode.get(languageCode)
- : null;
- }
-
- private boolean isValidLanguageCode(String languageCode) {
- return !TextUtils.isEmpty(languageCode) && mCodeToRepresentation.containsKey(languageCode);
- }
-
- private boolean isValidLanguageUMAHashCode(String languageCode) {
- return !TextUtils.isEmpty(languageCode) && mCodeToUMAHashCode.containsKey(languageCode);
- }
-
- private boolean canSetLanguage(String sourceCode, String targetCode) {
- return isValidLanguageCode(sourceCode) && isValidLanguageCode(targetCode);
- }
-
- @Override
- public String toString() {
- return new StringBuilder()
- .append(sourceLanguageCode())
- .append(" -> ")
- .append(targetLanguageCode())
- .append(" - ")
- .append("Never Language:")
- .append(mOptions[Type.NEVER_LANGUAGE])
- .append(" Always Language:")
- .append(mOptions[Type.ALWAYS_LANGUAGE])
- .append(" Never Domain:")
- .append(mOptions[Type.NEVER_DOMAIN])
- .toString();
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateTabContent.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateTabContent.java
deleted file mode 100644
index 4cde0b46193..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateTabContent.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-/**
- * The content of the tab shown in the TranslateTabLayout.
- */
-public class TranslateTabContent extends FrameLayout {
- private TextView mTextView;
- private ProgressBar mProgressBar;
-
- /**
- * Constructor for inflating from XML.
- */
- public TranslateTabContent(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mTextView = (TextView) findViewById(R.id.weblayer_translate_infobar_tab_text);
- mProgressBar = (ProgressBar) findViewById(R.id.weblayer_translate_infobar_tab_progressbar);
- }
-
- /**
- * Sets the text color for all the states (normal, selected, focused) to be this color.
- * @param colors The color state list of the title text.
- */
- public void setTextColor(ColorStateList colors) {
- mTextView.setTextColor(colors);
- }
-
- /**
- * Set the title text for this tab.
- * @param tabTitle The new title string.
- */
- public void setText(CharSequence tabTitle) {
- mTextView.setText(tabTitle);
- }
-
- /** Hide progress bar and show text. */
- public void hideProgressBar() {
- mProgressBar.setVisibility(View.INVISIBLE);
- mTextView.setVisibility(View.VISIBLE);
- }
-
- /** Show progress bar and hide text. */
- public void showProgressBar() {
- mTextView.setVisibility(View.INVISIBLE);
- mProgressBar.setVisibility(View.VISIBLE);
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateTabLayout.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateTabLayout.java
deleted file mode 100644
index 37c27f37cc6..00000000000
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateTabLayout.java
+++ /dev/null
@@ -1,240 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-
-import androidx.annotation.NonNull;
-
-import com.google.android.material.tabs.TabLayout;
-
-import org.chromium.base.StrictModeContext;
-import org.chromium.components.browser_ui.widget.animation.Interpolators;
-
-/**
- * TabLayout shown in the TranslateCompactInfoBar.
- */
-public class TranslateTabLayout extends TabLayout {
- /** The tab in which a spinning progress bar is showing. */
- private Tab mTabShowingProgressBar;
-
- /** The amount of waiting time before starting the scrolling animation. */
- private static final long START_POSITION_WAIT_DURATION_MS = 1000;
-
- /** The amount of time it takes to scroll to the end during the scrolling animation. */
- private static final long SCROLL_DURATION_MS = 300;
-
- /** We define the keyframes of the scrolling animation in this object. */
- ObjectAnimator mScrollToEndAnimator;
-
- /** Start padding of a Tab. Used for width calculation only. Will not be applied to views. */
- private int mTabPaddingStart;
-
- /** End padding of a Tab. Used for width calculation only. Will not be applied to views. */
- private int mTabPaddingEnd;
-
- /**
- * Constructor for inflating from XML.
- */
- @SuppressLint("CustomViewStyleable") // TODO(crbug.com/807725): Remove and fix.
- public TranslateTabLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(
- attrs, R.styleable.TabLayout, 0, R.style.Widget_Design_TabLayout);
- mTabPaddingStart = mTabPaddingEnd =
- a.getDimensionPixelSize(R.styleable.TabLayout_tabPadding, 0);
- mTabPaddingStart =
- a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingStart, mTabPaddingStart);
- mTabPaddingEnd =
- a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingEnd, mTabPaddingEnd);
- }
-
- /**
- * Add new Tabs with title strings.
- * @param titles Titles of the tabs to be added.
- */
- public void addTabs(CharSequence... titles) {
- for (CharSequence title : titles) {
- addTabWithTitle(title);
- }
- }
-
- /**
- * Add a new Tab with the title string.
- * @param tabTitle Title string of the new tab.
- */
- public void addTabWithTitle(CharSequence tabTitle) {
- TranslateTabContent tabContent;
- // LayoutInflater may trigger accessing the disk.
- try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
- tabContent =
- (TranslateTabContent) LayoutInflater.from(getContext())
- .inflate(R.layout.weblayer_infobar_translate_tab_content, this, false);
- }
- // Set text color using tabLayout's ColorStateList. So that the title text will change
- // color when selected and unselected.
- tabContent.setTextColor(getTabTextColors());
- tabContent.setText(tabTitle);
-
- Tab tab = newTab();
- tab.setCustomView(tabContent);
- tab.setContentDescription(tabTitle);
- super.addTab(tab);
- }
-
- /**
- * Replace the title string of a tab.
- * @param tabPos The position of the tab to modify.
- * @param tabTitle The new title string.
- */
- public void replaceTabTitle(int tabPos, CharSequence tabTitle) {
- if (tabPos < 0 || tabPos >= getTabCount()) {
- return;
- }
- Tab tab = getTabAt(tabPos);
- ((TranslateTabContent) tab.getCustomView()).setText(tabTitle);
- tab.setContentDescription(tabTitle);
- }
-
- /**
- * Show the spinning progress bar on a specified tab.
- * @param tabPos The position of the tab to show the progress bar.
- */
- public void showProgressBarOnTab(int tabPos) {
- if (tabPos < 0 || tabPos >= getTabCount() || mTabShowingProgressBar != null) {
- return;
- }
- mTabShowingProgressBar = getTabAt(tabPos);
-
- // TODO(martiw) See if we need to setContentDescription as "Translating" here.
-
- if (tabIsSupported(mTabShowingProgressBar)) {
- ((TranslateTabContent) mTabShowingProgressBar.getCustomView()).showProgressBar();
- }
- }
-
- /**
- * Hide the spinning progress bar in the tabs.
- */
- public void hideProgressBar() {
- if (mTabShowingProgressBar == null) return;
-
- if (tabIsSupported(mTabShowingProgressBar)) {
- ((TranslateTabContent) mTabShowingProgressBar.getCustomView()).hideProgressBar();
- }
-
- mTabShowingProgressBar = null;
- }
-
- // Overridden to block children's touch event when showing progress bar.
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // Allow touches to propagate to children only if the layout can be interacted with.
- if (mTabShowingProgressBar != null) {
- return true;
- }
- endScrollingAnimationIfPlaying();
- return super.onInterceptTouchEvent(ev);
- }
-
- /** Check if the tab is supported in TranslateTabLayout. */
- private boolean tabIsSupported(Tab tab) {
- return (tab.getCustomView() instanceof TranslateTabContent);
- }
-
- // Overridden to make sure only supported Tabs can be added.
- @Override
- public void addTab(@NonNull Tab tab, int position, boolean setSelected) {
- if (!tabIsSupported(tab)) {
- throw new IllegalArgumentException();
- }
- super.addTab(tab, position, setSelected);
- }
-
- // Overrided to make sure only supported Tabs can be added.
- @Override
- public void addTab(@NonNull Tab tab, boolean setSelected) {
- if (!tabIsSupported(tab)) {
- throw new IllegalArgumentException();
- }
- super.addTab(tab, setSelected);
- }
-
- /**
- * Calculate and return the width of a specified tab. Tab doesn't provide a means of getting
- * the width so we need to calculate the width by summing up the tab paddings and content width.
- * @param position Tab position.
- * @return Tab's width in pixels.
- */
- private int getTabWidth(int position) {
- if (getTabAt(position) == null) return 0;
- return getTabAt(position).getCustomView().getWidth() + mTabPaddingStart + mTabPaddingEnd;
- }
-
- /**
- * Calculate the total width of all tabs and return it.
- * @return Total width of all tabs in pixels.
- */
- private int getTabsTotalWidth() {
- int totalWidth = 0;
- for (int i = 0; i < getTabCount(); i++) {
- totalWidth += getTabWidth(i);
- }
- return totalWidth;
- }
-
- /**
- * Calculate the maximum scroll distance (by subtracting layout width from total width of tabs)
- * and return it.
- * @return Maximum scroll distance in pixels.
- */
- private int maxScrollDistance() {
- int scrollDistance = getTabsTotalWidth() - getWidth();
- return scrollDistance > 0 ? scrollDistance : 0;
- }
-
- /**
- * Perform the scrolling animation if this tablayout has any scrollable distance.
- */
- // TODO(crbug.com/900912): Figure out whether setScrollX is actually available.
- @SuppressLint("ObjectAnimatorBinding")
- public void startScrollingAnimationIfNeeded() {
- int maxScrollDistance = maxScrollDistance();
- if (maxScrollDistance == 0) {
- return;
- }
- // The steps of the scrolling animation:
- // 1. wait for START_POSITION_WAIT_DURATION_MS.
- // 2. scroll to the end in SCROLL_DURATION_MS.
- mScrollToEndAnimator = ObjectAnimator.ofInt(this, "scrollX",
- getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : maxScrollDistance);
- mScrollToEndAnimator.setStartDelay(START_POSITION_WAIT_DURATION_MS);
- mScrollToEndAnimator.setDuration(SCROLL_DURATION_MS);
- mScrollToEndAnimator.setInterpolator(Interpolators.DECELERATE_INTERPOLATOR);
- mScrollToEndAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mScrollToEndAnimator = null;
- }
- });
- mScrollToEndAnimator.start();
- }
-
- /**
- * End the scrolling animation if it is playing.
- */
- public void endScrollingAnimationIfPlaying() {
- if (mScrollToEndAnimator != null) mScrollToEndAnimator.end();
- }
-}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
index 4f3d7b439f1..496c52078b3 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
@@ -11,6 +11,8 @@ import android.os.Bundle;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -18,12 +20,15 @@ import android.widget.TextView;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.widget.ImageViewCompat;
import org.chromium.base.LifetimeAssert;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
+import org.chromium.components.content_settings.ContentSettingsType;
+import org.chromium.components.embedder_support.util.Origin;
import org.chromium.components.omnibox.SecurityButtonAnimationDelegate;
import org.chromium.components.omnibox.SecurityStatusIcon;
import org.chromium.components.page_info.PageInfoController;
@@ -68,7 +73,16 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
}
@Override
- public IObjectWrapper /* View */ createUrlBarView(Bundle options) {
+ @Deprecated
+ public IObjectWrapper /* View */ deprecatedCreateUrlBarView(Bundle options) {
+ return createUrlBarView(
+ options, /* OnLongClickListener */ null, /* OnLongClickListener */ null);
+ }
+
+ @Override
+ public IObjectWrapper /* View */ createUrlBarView(Bundle options,
+ @Nullable IObjectWrapper /* OnLongClickListener */ clickListener,
+ @Nullable IObjectWrapper /* OnLongClickListener */ longClickListener) {
StrictModeWorkaround.apply();
if (mBrowserImpl == null) {
throw new IllegalStateException("UrlBarView cannot be created without a valid Browser");
@@ -76,7 +90,7 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
Context context = mBrowserImpl.getContext();
if (context == null) throw new IllegalStateException("BrowserFragment not attached yet.");
- UrlBarView urlBarView = new UrlBarView(context, options);
+ UrlBarView urlBarView = new UrlBarView(context, options, clickListener, longClickListener);
return ObjectWrapper.wrap(urlBarView);
}
@@ -92,8 +106,12 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
private TextView mUrlTextView;
private ImageButton mSecurityButton;
private final SecurityButtonAnimationDelegate mSecurityButtonAnimationDelegate;
+ OnClickListener mUrlBarClickListener;
+ OnLongClickListener mUrlBarLongClickListener;
- public UrlBarView(@NonNull Context context, Bundle options) {
+ public UrlBarView(@NonNull Context context, @NonNull Bundle options,
+ @Nullable IObjectWrapper /* OnClickListener */ clickListener,
+ @Nullable IObjectWrapper /* OnLongClickListener */ longClickListener) {
super(context);
setGravity(Gravity.CENTER_HORIZONTAL);
@@ -110,6 +128,9 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
mSecurityButton = (ImageButton) findViewById(R.id.security_button);
mSecurityButtonAnimationDelegate = new SecurityButtonAnimationDelegate(
mSecurityButton, mUrlTextView, R.dimen.security_status_icon_size);
+ mUrlBarClickListener = ObjectWrapper.unwrap(clickListener, OnClickListener.class);
+ mUrlBarLongClickListener =
+ ObjectWrapper.unwrap(longClickListener, OnLongClickListener.class);
updateView();
}
@@ -161,9 +182,24 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
}
if (mShowPageInfoWhenUrlTextClicked) {
+ // Set clicklisteners on the entire UrlBarView.
+ assert (mUrlBarClickListener == null);
+ mSecurityButton.setClickable(false);
setOnClickListener(v -> { showPageInfoUi(v); });
+
+ if (mUrlBarLongClickListener != null) {
+ setOnLongClickListener(mUrlBarLongClickListener);
+ }
} else {
+ // Set a clicklistener on the security status and TextView separately. This mode
+ // can be used to create an editable URL bar using WebLayer.
mSecurityButton.setOnClickListener(v -> { showPageInfoUi(v); });
+ if (mUrlBarClickListener != null) {
+ mUrlTextView.setOnClickListener(mUrlBarClickListener);
+ }
+ if (mUrlBarLongClickListener != null) {
+ mUrlTextView.setOnLongClickListener(mUrlBarLongClickListener);
+ }
}
}
@@ -173,7 +209,18 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
webContents,
/* contentPublisher= */ null, PageInfoController.OpenedFromSource.TOOLBAR,
PageInfoControllerDelegateImpl.create(webContents),
- new PermissionParamsListBuilderDelegate(mBrowserImpl.getProfile()));
+ new PermissionParamsListBuilderDelegate(mBrowserImpl.getProfile()) {
+ @Override
+ public String getDelegateAppName(
+ Origin origin, @ContentSettingsType int type) {
+ if (type == ContentSettingsType.GEOLOCATION
+ && WebLayerImpl.isLocationPermissionManaged(origin)) {
+ return WebLayerImpl.getClientApplicationName();
+ }
+
+ return null;
+ }
+ });
}
@DrawableRes
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerFactoryImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerFactoryImpl.java
index 9e79ff718ec..07c937bf42c 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerFactoryImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerFactoryImpl.java
@@ -50,6 +50,11 @@ public final class WebLayerFactoryImpl extends IWebLayerFactory.Stub {
@Override
public boolean isClientSupported() {
StrictModeWorkaround.apply();
+ // Client changes were required to support WebLayer in a split.
+ if (ProductConfig.IS_BUNDLE && WebLayerBundleUtils.IS_WEBLAYER_IN_SPLIT
+ && sClientMajorVersion < 86) {
+ return false;
+ }
int implMajorVersion = getImplementationMajorVersion();
// While the client always calls this method, the most recently shipped product gets to
// decide compatibility. If we instead let the implementation always decide, then we would
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
index c9223c62146..1c3ba5744fb 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
@@ -38,10 +38,12 @@ import org.chromium.base.StrictModeContext;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
+import org.chromium.base.compat.ApiHelperForO;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.components.embedder_support.application.ClassLoaderContextWrapperFactory;
import org.chromium.components.embedder_support.application.FirebaseConfig;
+import org.chromium.components.embedder_support.util.Origin;
import org.chromium.content_public.browser.BrowserStartupController;
import org.chromium.content_public.browser.ChildProcessCreationParams;
import org.chromium.content_public.browser.DeviceUtils;
@@ -122,12 +124,6 @@ public final class WebLayerImpl extends IWebLayer.Stub {
WebLayerImpl() {}
@Override
- public void loadAsyncV80(
- IObjectWrapper appContextWrapper, IObjectWrapper loadedCallbackWrapper) {
- loadAsync(appContextWrapper, null, loadedCallbackWrapper);
- }
-
- @Override
public void loadAsync(IObjectWrapper appContextWrapper, IObjectWrapper remoteContextWrapper,
IObjectWrapper loadedCallbackWrapper) {
StrictModeWorkaround.apply();
@@ -152,11 +148,6 @@ public final class WebLayerImpl extends IWebLayer.Stub {
}
@Override
- public void loadSyncV80(IObjectWrapper appContextWrapper) {
- loadSync(appContextWrapper, null);
- }
-
- @Override
public void loadSync(IObjectWrapper appContextWrapper, IObjectWrapper remoteContextWrapper) {
StrictModeWorkaround.apply();
init(appContextWrapper, remoteContextWrapper);
@@ -207,7 +198,9 @@ public final class WebLayerImpl extends IWebLayer.Stub {
notifyWebViewRunningInProcess(remoteContext.getClassLoader());
}
- Context appContext = minimalInitForContext(appContextWrapper, remoteContextWrapper);
+ remoteContext = processRemoteContext(remoteContext);
+ Context appContext = minimalInitForContext(
+ ObjectWrapper.unwrap(appContextWrapper, Context.class), remoteContext);
PackageInfo packageInfo = WebViewFactory.getLoadedPackageInfo();
// If a remote context is not provided, the client is an older version that loads the native
@@ -221,7 +214,8 @@ public final class WebLayerImpl extends IWebLayer.Stub {
FirebaseConfig.getFirebaseAppIdForPackage(packageInfo.packageName));
// TODO: The call to onResourcesLoaded() can be slow, we may need to parallelize this with
// other expensive startup tasks.
- R.onResourcesLoaded(forceCorrectPackageId(remoteContext));
+ org.chromium.weblayer_private.base.R.onResourcesLoaded(
+ forceCorrectPackageId(remoteContext));
SelectionPopupController.setMustUseWebContentsContext();
ResourceBundle.setAvailablePakLocales(new String[] {}, ProductConfig.UNCOMPRESSED_LOCALES);
@@ -304,17 +298,12 @@ public final class WebLayerImpl extends IWebLayer.Stub {
}
@Override
- public ICrashReporterController getCrashReporterControllerV80(IObjectWrapper appContext) {
- StrictModeWorkaround.apply();
- return getCrashReporterController(appContext, null);
- }
-
- @Override
public ICrashReporterController getCrashReporterController(
IObjectWrapper appContext, IObjectWrapper remoteContext) {
StrictModeWorkaround.apply();
// This is a no-op if init has already happened.
- WebLayerImpl.minimalInitForContext(appContext, remoteContext);
+ WebLayerImpl.minimalInitForContext(ObjectWrapper.unwrap(appContext, Context.class),
+ processRemoteContext(ObjectWrapper.unwrap(remoteContext, Context.class)));
return CrashReporterControllerImpl.getInstance();
}
@@ -371,20 +360,6 @@ public final class WebLayerImpl extends IWebLayer.Stub {
WebLayerImplJni.get().registerExternalExperimentIDs(trialName, experimentIDs);
}
- /**
- * Creates a remote context. This should only be used for backwards compatibility when the
- * client was not sending the remote context.
- */
- public static Context createRemoteContextV80(Context appContext) {
- try {
- return appContext.createPackageContext(
- WebViewFactory.getLoadedPackageInfo().packageName,
- Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
- } catch (PackageManager.NameNotFoundException e) {
- throw new AndroidRuntimeException(e);
- }
- }
-
public static Intent createIntent() {
if (sClient == null) {
throw new IllegalStateException("WebLayer should have been initialized already.");
@@ -429,6 +404,13 @@ public final class WebLayerImpl extends IWebLayer.Stub {
.toString();
}
+ public static boolean isLocationPermissionManaged(Origin origin) {
+ if (origin == null) {
+ return false;
+ }
+ return WebLayerImplJni.get().isLocationPermissionManaged(origin.toString());
+ }
+
/**
* Converts the given id into a resource ID that can be shown in system UI, such as
* notifications.
@@ -467,16 +449,11 @@ public final class WebLayerImpl extends IWebLayer.Stub {
* Performs the minimal initialization needed for a context. This is used for example in
* CrashReporterControllerImpl, so it can be used before full WebLayer initialization.
*/
- private static Context minimalInitForContext(
- IObjectWrapper appContextWrapper, IObjectWrapper remoteContextWrapper) {
+ private static Context minimalInitForContext(Context appContext, Context remoteContext) {
if (ContextUtils.getApplicationContext() != null) {
return ContextUtils.getApplicationContext();
}
- Context appContext = ObjectWrapper.unwrap(appContextWrapper, Context.class);
- Context remoteContext = ObjectWrapper.unwrap(remoteContextWrapper, Context.class);
- if (remoteContext == null) {
- remoteContext = createRemoteContextV80(appContext);
- }
+ assert remoteContext != null;
ClassLoaderContextWrapperFactory.setResourceOverrideContext(remoteContext);
// Wrap the app context so that it can be used to load WebLayer implementation classes.
appContext = ClassLoaderContextWrapperFactory.get(appContext);
@@ -685,7 +662,9 @@ public final class WebLayerImpl extends IWebLayer.Stub {
}
private static void notifyWebViewRunningInProcess(ClassLoader webViewClassLoader) {
- try {
+ // TODO(crbug.com/1112001): Investigate why loading classes causes strict mode
+ // violations in some situations.
+ try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
Class<?> webViewChromiumFactoryProviderClass =
Class.forName("com.android.webview.chromium.WebViewChromiumFactoryProvider",
true, webViewClassLoader);
@@ -693,8 +672,20 @@ public final class WebLayerImpl extends IWebLayer.Stub {
"setWebLayerRunningInSameProcess");
setter.invoke(null);
} catch (Exception e) {
- Log.w(TAG, "Unable to notify WebView running in process", e);
+ Log.w(TAG, "Unable to notify WebView running in process.");
+ }
+ }
+
+ private static Context processRemoteContext(Context remoteContext) {
+ // If WebLayer is in a DFM, make sure the correct resources are used.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ try {
+ return ApiHelperForO.createContextForSplit(remoteContext, "weblayer");
+ } catch (PackageManager.NameNotFoundException e) {
+ // WebLayer is not in a split, the original context will have the resources.
+ }
}
+ return remoteContext;
}
@CalledByNative
@@ -710,5 +701,6 @@ public final class WebLayerImpl extends IWebLayer.Stub {
void setIsWebViewCompatMode(boolean value);
String getUserAgentString();
void registerExternalExperimentIDs(String trialName, int[] experimentIDs);
+ boolean isLocationPermissionManaged(String origin);
}
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationBuilder.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationWrapperBuilder.java
index 50984bb6403..fac8a475265 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationBuilder.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationWrapperBuilder.java
@@ -15,32 +15,32 @@ import android.webkit.WebViewFactory;
import androidx.annotation.NonNull;
import org.chromium.base.ContextUtils;
-import org.chromium.components.browser_ui.notifications.ChromeNotificationBuilder;
-import org.chromium.components.browser_ui.notifications.NotificationBuilder;
import org.chromium.components.browser_ui.notifications.NotificationManagerProxyImpl;
import org.chromium.components.browser_ui.notifications.NotificationMetadata;
+import org.chromium.components.browser_ui.notifications.NotificationWrapperBuilder;
+import org.chromium.components.browser_ui.notifications.NotificationWrapperStandardBuilder;
import org.chromium.components.browser_ui.notifications.channels.ChannelsInitializer;
/** A notification builder for WebLayer which has extra logic to make icons work correctly. */
-final class WebLayerNotificationBuilder extends NotificationBuilder {
+final class WebLayerNotificationWrapperBuilder extends NotificationWrapperStandardBuilder {
/** Creates a notification builder. */
- public static WebLayerNotificationBuilder create(
+ public static WebLayerNotificationWrapperBuilder create(
@WebLayerNotificationChannels.ChannelId String channelId,
@NonNull NotificationMetadata metadata) {
Context appContext = ContextUtils.getApplicationContext();
ChannelsInitializer initializer =
new ChannelsInitializer(new NotificationManagerProxyImpl(appContext),
WebLayerNotificationChannels.getInstance(), appContext.getResources());
- return new WebLayerNotificationBuilder(appContext, channelId, initializer, metadata);
+ return new WebLayerNotificationWrapperBuilder(appContext, channelId, initializer, metadata);
}
- private WebLayerNotificationBuilder(Context context, String channelId,
+ private WebLayerNotificationWrapperBuilder(Context context, String channelId,
ChannelsInitializer channelsInitializer, NotificationMetadata metadata) {
super(context, channelId, channelsInitializer, metadata);
}
@Override
- public ChromeNotificationBuilder setSmallIcon(int icon) {
+ public NotificationWrapperBuilder setSmallIcon(int icon) {
if (WebLayerImpl.isAndroidResource(icon)) {
super.setSmallIcon(icon);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@@ -54,7 +54,8 @@ final class WebLayerNotificationBuilder extends NotificationBuilder {
@Override
@SuppressWarnings("deprecation")
- public ChromeNotificationBuilder addAction(int icon, CharSequence title, PendingIntent intent) {
+ public NotificationWrapperBuilder addAction(
+ int icon, CharSequence title, PendingIntent intent) {
if (WebLayerImpl.isAndroidResource(icon)) {
super.addAction(icon, title, intent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerSiteSettingsClient.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerSiteSettingsClient.java
index cabbef5f87a..3d03b906ec3 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerSiteSettingsClient.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerSiteSettingsClient.java
@@ -11,12 +11,13 @@ import androidx.annotation.Nullable;
import androidx.preference.Preference;
import org.chromium.base.Callback;
+import org.chromium.base.ContextUtils;
import org.chromium.components.browser_ui.settings.ManagedPreferenceDelegate;
import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory.Type;
import org.chromium.components.browser_ui.site_settings.SiteSettingsClient;
import org.chromium.components.browser_ui.site_settings.SiteSettingsHelpClient;
-import org.chromium.components.browser_ui.site_settings.SiteSettingsPrefClient;
import org.chromium.components.browser_ui.site_settings.WebappSettingsClient;
+import org.chromium.components.content_settings.ContentSettingsType;
import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
import org.chromium.components.embedder_support.util.Origin;
@@ -26,9 +27,8 @@ import java.util.Set;
/**
* A SiteSettingsClient instance that contains WebLayer-specific Site Settings logic.
*/
-public class WebLayerSiteSettingsClient
- implements SiteSettingsClient, ManagedPreferenceDelegate, SiteSettingsHelpClient,
- SiteSettingsPrefClient, WebappSettingsClient {
+public class WebLayerSiteSettingsClient implements SiteSettingsClient, ManagedPreferenceDelegate,
+ SiteSettingsHelpClient, WebappSettingsClient {
private final BrowserContextHandle mBrowserContextHandle;
public WebLayerSiteSettingsClient(BrowserContextHandle browserContextHandle) {
@@ -53,11 +53,6 @@ public class WebLayerSiteSettingsClient
}
@Override
- public SiteSettingsPrefClient getSiteSettingsPrefClient() {
- return this;
- }
-
- @Override
public WebappSettingsClient getWebappSettingsClient() {
return this;
}
@@ -86,6 +81,33 @@ public class WebLayerSiteSettingsClient
return null;
}
+ @Override
+ public String getAppName() {
+ return WebLayerImpl.getClientApplicationName();
+ }
+
+ @Override
+ @Nullable
+ public String getDelegateAppNameForOrigin(Origin origin, @ContentSettingsType int type) {
+ if (WebLayerImpl.isLocationPermissionManaged(origin)
+ && type == ContentSettingsType.GEOLOCATION) {
+ return WebLayerImpl.getClientApplicationName();
+ }
+
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public String getDelegatePackageNameForOrigin(Origin origin, @ContentSettingsType int type) {
+ if (WebLayerImpl.isLocationPermissionManaged(origin)
+ && type == ContentSettingsType.GEOLOCATION) {
+ return ContextUtils.getApplicationContext().getPackageName();
+ }
+
+ return null;
+ }
+
// ManagedPrefrenceDelegate implementation:
// A no-op because WebLayer doesn't support managed preferences.
@@ -118,22 +140,6 @@ public class WebLayerSiteSettingsClient
@Override
public void launchProtectedContentHelpAndFeedbackActivity(Activity currentActivity) {}
- // SiteSettingsPrefClient implementation:
-
- // The quiet notification UI is a Chrome-specific feature for now.
- @Override
- public boolean getEnableQuietNotificationPermissionUi() {
- return false;
- }
- @Override
- public void setEnableQuietNotificationPermissionUi(boolean newValue) {}
- @Override
- public void clearEnableNotificationPermissionUi() {}
-
- // WebLayer doesn't support notifications yet.
- @Override
- public void setNotificationsVibrateEnabled(boolean newValue) {}
-
// WebappSettingsClient implementation:
// A no-op since WebLayer doesn't support webapps.
@@ -146,16 +152,4 @@ public class WebLayerSiteSettingsClient
public Set<String> getAllDelegatedNotificationOrigins() {
return Collections.EMPTY_SET;
}
-
- @Override
- @Nullable
- public String getNotificationDelegateAppNameForOrigin(Origin origin) {
- return null;
- }
-
- @Override
- @Nullable
- public String getNotificationDelegatePackageNameForOrigin(Origin origin) {
- return null;
- }
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerTabModalPresenter.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerTabModalPresenter.java
index b1be612a9ff..aef1e1b037b 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerTabModalPresenter.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerTabModalPresenter.java
@@ -5,16 +5,15 @@
package org.chromium.weblayer_private;
import android.content.Context;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import org.chromium.base.StrictModeContext;
import org.chromium.components.browser_ui.modaldialog.R;
import org.chromium.components.browser_ui.modaldialog.TabModalPresenter;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.common.BrowserControlsState;
+import org.chromium.ui.LayoutInflaterUtils;
import org.chromium.ui.modelutil.PropertyModel;
/**
@@ -53,11 +52,8 @@ public class WebLayerTabModalPresenter extends TabModalPresenter {
}
private FrameLayout loadDialogContainer() {
- // LayoutInflater may trigger accessing the disk.
- try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
- return (FrameLayout) LayoutInflater.from(mContext).inflate(
- R.layout.modal_dialog_container, null);
- }
+ return (FrameLayout) LayoutInflaterUtils.inflate(
+ mContext, R.layout.modal_dialog_container, null);
}
@Override
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/BrowsingDataType.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/BrowsingDataType.java
index 840bfae909c..cea8ff43b11 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/BrowsingDataType.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/BrowsingDataType.java
@@ -9,9 +9,11 @@ import androidx.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-@IntDef({BrowsingDataType.COOKIES_AND_SITE_DATA, BrowsingDataType.CACHE})
+@IntDef({BrowsingDataType.COOKIES_AND_SITE_DATA, BrowsingDataType.CACHE,
+ BrowsingDataType.SITE_SETTINGS})
@Retention(RetentionPolicy.SOURCE)
public @interface BrowsingDataType {
int COOKIES_AND_SITE_DATA = 0;
int CACHE = 1;
+ int SITE_SETTINGS = 2;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/GoogleAccountServiceType.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/GoogleAccountServiceType.java
new file mode 100644
index 00000000000..f7e0c81de68
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/GoogleAccountServiceType.java
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.weblayer_private.interfaces;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@IntDef({GoogleAccountServiceType.SIGNOUT, GoogleAccountServiceType.ADD_SESSION,
+ GoogleAccountServiceType.DEFAULT})
+@Retention(RetentionPolicy.SOURCE)
+public @interface GoogleAccountServiceType {
+ int SIGNOUT = 0;
+ int ADD_SESSION = 1;
+ int DEFAULT = 2;
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl
index ed9a123fe9c..40eb4208e27 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl
@@ -36,4 +36,7 @@ interface IBrowser {
void setBottomView(in IObjectWrapper view) = 10;
ITab createTab() = 11;
+
+ void setTopViewAndScrollingBehavior(in IObjectWrapper view, in int minHeight,
+ in boolean pinToContentTop, in boolean animate) = 12;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IErrorPageCallbackClient.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IErrorPageCallbackClient.aidl
index 1dfc22b1a2e..f361f315806 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IErrorPageCallbackClient.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IErrorPageCallbackClient.aidl
@@ -4,10 +4,13 @@
package org.chromium.weblayer_private.interfaces;
+import org.chromium.weblayer_private.interfaces.IClientNavigation;
+
/**
* Allows the client to override the default way of handling user interactions
* with error pages (such as SSL interstitials).
*/
interface IErrorPageCallbackClient {
boolean onBackToSafety() = 0;
+ String getErrorPageContent(IClientNavigation navigation) = 1;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IFaviconFetcher.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IFaviconFetcher.aidl
new file mode 100644
index 00000000000..eec59fea8b8
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IFaviconFetcher.aidl
@@ -0,0 +1,9 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.weblayer_private.interfaces;
+
+interface IFaviconFetcher {
+ void destroy() = 1;
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IFaviconFetcherClient.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IFaviconFetcherClient.aidl
new file mode 100644
index 00000000000..b94402cd747
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IFaviconFetcherClient.aidl
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.weblayer_private.interfaces;
+
+interface IFaviconFetcherClient {
+ void onDestroyed() = 1;
+ void onFaviconChanged(in Bitmap bitmap) = 2;
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IGoogleAccountsCallbackClient.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IGoogleAccountsCallbackClient.aidl
new file mode 100644
index 00000000000..50589c668b3
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IGoogleAccountsCallbackClient.aidl
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.weblayer_private.interfaces;
+
+interface IGoogleAccountsCallbackClient {
+ void onGoogleAccountsRequest(int serviceType, in String email, in String continueUrl, boolean isSameTab) = 0;
+ String getGaiaId() = 1;
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
index 9d42c486155..5c94e3418ea 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
@@ -29,4 +29,8 @@ interface INavigation {
boolean isDownload() = 9;
boolean wasStopCalled() = 10;
+
+ // @since 86
+ boolean isPageInitiated() = 11;
+ boolean isReload() = 12;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationController.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationController.aidl
index 653b9a6af12..e2ffa2a15fd 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationController.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationController.aidl
@@ -36,4 +36,11 @@ interface INavigationController {
// Added in 85.
boolean isNavigationEntrySkippable(int index) = 13;
+
+ // Added in 86.
+ void navigate2(in String uri,
+ in boolean shouldReplaceEntry,
+ in boolean disableIntentProcessing,
+ in boolean disableNetworkErrorAutoReload,
+ in boolean enableAutoPlay) = 14;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfile.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfile.aidl
index 6ec60700f85..269814d69db 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfile.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfile.aidl
@@ -36,4 +36,8 @@ interface IProfile {
void removeBrowserPersistenceStorage(in String[] ids,
in IObjectWrapper resultCallback) = 10;
void prepareForPossibleCrossOriginNavigation() = 11;
+
+ // Added in Version 86.
+ void getCachedFaviconForPageUri(in String uri,
+ in IObjectWrapper resultCallback) = 12;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl
index c029b9a6c18..21c50841f8b 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl
@@ -8,8 +8,11 @@ import java.util.List;
import org.chromium.weblayer_private.interfaces.IDownloadCallbackClient;
import org.chromium.weblayer_private.interfaces.IErrorPageCallbackClient;
+import org.chromium.weblayer_private.interfaces.IFaviconFetcher;
+import org.chromium.weblayer_private.interfaces.IFaviconFetcherClient;
import org.chromium.weblayer_private.interfaces.IFindInPageCallbackClient;
import org.chromium.weblayer_private.interfaces.IFullscreenCallbackClient;
+import org.chromium.weblayer_private.interfaces.IGoogleAccountsCallbackClient;
import org.chromium.weblayer_private.interfaces.IMediaCaptureCallbackClient;
import org.chromium.weblayer_private.interfaces.INavigationController;
import org.chromium.weblayer_private.interfaces.INavigationControllerClient;
@@ -57,8 +60,6 @@ interface ITab {
// Added in 85
boolean setData(in Map data) = 17;
-
- // Added in 85
Map getData() = 18;
void registerWebMessageCallback(in String jsObjectName,
in List<String> allowedOrigins,
@@ -66,4 +67,9 @@ interface ITab {
void unregisterWebMessageCallback(in String jsObjectName) = 20;
boolean canTranslate() = 21;
void showTranslateUi() = 22;
+
+ // Added in 86
+ void setGoogleAccountsCallbackClient(IGoogleAccountsCallbackClient client) = 23;
+ IFaviconFetcher createFaviconFetcher(IFaviconFetcherClient client) = 24;
+ void setTranslateTargetLanguage(in String targetLanguage) = 25;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IUrlBarController.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IUrlBarController.aidl
index 212e8c2f4ff..c69b042ef66 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IUrlBarController.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IUrlBarController.aidl
@@ -7,5 +7,13 @@ package org.chromium.weblayer_private.interfaces;
import org.chromium.weblayer_private.interfaces.IObjectWrapper;
interface IUrlBarController {
- IObjectWrapper /* View */ createUrlBarView(in Bundle options) = 0;
+
+ // Deprecated in 84, use createUrlBarView with three arguments.
+ IObjectWrapper /* View */ deprecatedCreateUrlBarView(in Bundle options) = 0;
+
+ // Since 86
+ IObjectWrapper /* View */ createUrlBarView(
+ in Bundle options,
+ in IObjectWrapper /* View.OnClickListener */ textClickListener,
+ in IObjectWrapper /* View.OnLongClickListener */ textLongClickListener) = 1;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl
index 7c8af14c1f6..965b11e0199 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl
@@ -16,12 +16,8 @@ import org.chromium.weblayer_private.interfaces.ISiteSettingsFragment;
import org.chromium.weblayer_private.interfaces.IWebLayerClient;
interface IWebLayer {
- // Deprecated, use loadAsync().
- void loadAsyncV80(in IObjectWrapper appContext,
- in IObjectWrapper loadedCallback) = 1;
-
- // Deprecated, use loadSync().
- void loadSyncV80(in IObjectWrapper appContext) = 2;
+ // ID 1 was loadAsyncV80 and was removed in M86.
+ // ID 2 was loadSyncV80 and was removed in M86.
// Creates the WebLayer counterpart to a BrowserFragment - a BrowserFragmentImpl
//
@@ -41,9 +37,7 @@ interface IWebLayer {
// Returns whether or not the DevTools remote debugging server is enabled.
boolean isRemoteDebuggingEnabled() = 6;
- // Deprecated, use getCrashReporterController().
- ICrashReporterController getCrashReporterControllerV80(
- in IObjectWrapper appContext) = 7;
+ // ID 7 was getCrashReporterControllerV80 and was removed in M86.
// Initializes WebLayer and starts loading.
//
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/NavigateParams.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/NavigateParams.java
index e79e137ce48..b5c9ab8fb46 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/NavigateParams.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/NavigateParams.java
@@ -15,7 +15,7 @@ import android.os.Parcelable;
* @since 83
*/
public class NavigateParams implements Parcelable {
- public boolean mShouldReplaceCurrentEntry = false;
+ public boolean mShouldReplaceCurrentEntry;
public static final Parcelable.Creator<NavigateParams> CREATOR =
new Parcelable.Creator<NavigateParams>() {
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py
index c375ef3b7aa..300806a9568 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py
@@ -149,7 +149,7 @@ def _CompareApiDumpForFiles(input_api, output_api, aidl_files):
def CheckChangeOnUpload(input_api, output_api):
filter_lambda = lambda x: input_api.FilterSourceFile(
- x, white_list=[r'.*\.aidl$' ])
+ x, files_to_check=[r'.*\.aidl$' ])
aidl_files = []
for f in input_api.AffectedFiles(include_deletes=False,
file_filter=filter_lambda):
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/SettingType.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/SettingType.java
index 1b37b08d9b3..b15bc939d5f 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/SettingType.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/SettingType.java
@@ -11,11 +11,12 @@ import java.lang.annotation.RetentionPolicy;
@IntDef({SettingType.BASIC_SAFE_BROWSING_ENABLED, SettingType.UKM_ENABLED,
SettingType.EXTENDED_REPORTING_SAFE_BROWSING_ENABLED,
- SettingType.REAL_TIME_SAFE_BROWSING_ENABLED})
+ SettingType.REAL_TIME_SAFE_BROWSING_ENABLED, SettingType.NETWORK_PREDICTION_ENABLED})
@Retention(RetentionPolicy.SOURCE)
public @interface SettingType {
int BASIC_SAFE_BROWSING_ENABLED = 0;
int UKM_ENABLED = 1;
int EXTENDED_REPORTING_SAFE_BROWSING_ENABLED = 2;
int REAL_TIME_SAFE_BROWSING_ENABLED = 3;
+ int NETWORK_PREDICTION_ENABLED = 4;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl
index ac1cd24f40f..53eff3330ed 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl
@@ -44,4 +44,13 @@ interface ITestWebLayer {
void forceNetworkConnectivityState(in boolean networkAvailable) = 13;
boolean canInfoBarContainerScroll(in ITab tab) = 14;
+
+ String getDisplayedUrl(IObjectWrapper /* View */ urlBarView) = 15;
+
+ // Returns the target language of the currently-showing translate infobar, or null if no translate
+ // infobar is currently showing.
+ String getTranslateInfoBarTargetLanguage(in ITab tab) = 16;
+
+ // Returns true if a fullscreen toast was shown for |tab|.
+ boolean didShowFullscreenToast(in ITab tab) = 17;
}
diff --git a/chromium/weblayer/browser/java/res/drawable/weblayer_infobar_wrapper_bg.xml b/chromium/weblayer/browser/java/res/drawable/weblayer_infobar_wrapper_bg.xml
deleted file mode 100644
index e119c1148fa..00000000000
--- a/chromium/weblayer/browser/java/res/drawable/weblayer_infobar_wrapper_bg.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
- Use of this source code is governed by a BSD-style license that can be
- found in the LICENSE file. -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
- <item>
- <bitmap
- android:src="@drawable/infobar_shadow_top"
- android:gravity="top|fill_horizontal"
- android:tileMode="disabled" />
- </item>
- <item
- android:top="@dimen/infobar_shadow_height"
- android:drawable="@color/infobar_background_color" />
-</layer-list>
diff --git a/chromium/weblayer/browser/java/res/layout/weblayer_infobar_translate_compact_content.xml b/chromium/weblayer/browser/java/res/layout/weblayer_infobar_translate_compact_content.xml
index 82149b5b142..f124f32821a 100644
--- a/chromium/weblayer/browser/java/res/layout/weblayer_infobar_translate_compact_content.xml
+++ b/chromium/weblayer/browser/java/res/layout/weblayer_infobar_translate_compact_content.xml
@@ -11,7 +11,7 @@
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- TODO(huayinz): Change app:tabIndicatorColor to some common color reference -->
- <org.chromium.weblayer_private.TranslateTabLayout
+ <org.chromium.components.translate.TranslateTabLayout
android:id="@+id/weblayer_translate_infobar_tabs"
android:layout_width="0dp"
android:layout_height="match_parent"
diff --git a/chromium/weblayer/browser/java/res/layout/weblayer_infobar_translate_tab_content.xml b/chromium/weblayer/browser/java/res/layout/weblayer_infobar_translate_tab_content.xml
deleted file mode 100644
index 3be8f467c43..00000000000
--- a/chromium/weblayer/browser/java/res/layout/weblayer_infobar_translate_tab_content.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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. -->
-
-<org.chromium.weblayer_private.TranslateTabContent
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/weblayer_translate_tabcontent"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <!-- Add both the textView and progressBar to the tab, and only keep one of them visible.
- This way the width of the Tab will always be fixed no matter which one is visible. -->
- <TextView
- android:id="@+id/weblayer_translate_infobar_tab_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:textAppearance="@style/TextAppearance.Design.Tab"
- android:visibility="visible"
- android:singleLine="true" />
- <ProgressBar
- android:id="@+id/weblayer_translate_infobar_tab_progressbar"
- android:layout_width="@dimen/infobar_small_icon_size"
- android:layout_height="@dimen/infobar_small_icon_size"
- android:layout_gravity="center"
- android:indeterminate="true"
- android:visibility="invisible" />
-</org.chromium.weblayer_private.TranslateTabContent>
diff --git a/chromium/weblayer/browser/java/res/layout/weblayer_translate_menu_item.xml b/chromium/weblayer/browser/java/res/layout/weblayer_translate_menu_item.xml
deleted file mode 100644
index a7948450da3..00000000000
--- a/chromium/weblayer/browser/java/res/layout/weblayer_translate_menu_item.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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. -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/WebLayerAppMenuItem"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
-
- <TextView
- android:id="@+id/weblayer_menu_item_text"
- android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:gravity="center_vertical"
- android:paddingTop="13dp"
- android:paddingBottom="13dp" />
-
-</FrameLayout>
diff --git a/chromium/weblayer/browser/java/res/layout/weblayer_translate_menu_item_checked.xml b/chromium/weblayer/browser/java/res/layout/weblayer_translate_menu_item_checked.xml
deleted file mode 100644
index a4bd2cf4692..00000000000
--- a/chromium/weblayer/browser/java/res/layout/weblayer_translate_menu_item_checked.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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. -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <LinearLayout
- style="@style/WebLayerAppMenuItem"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
-
- <TextView
- android:id="@+id/weblayer_menu_item_text"
- android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="start"
- android:gravity="center_vertical"
- android:paddingTop="13dp"
- android:paddingBottom="13dp"
- android:paddingEnd="16dp" />
- <org.chromium.ui.widget.ChromeImageView
- android:id="@+id/weblayer_menu_item_icon"
- android:src="@drawable/ic_check_googblue_24dp"
- android:layout_width="24dp"
- android:layout_height="match_parent"
- android:layout_gravity="end"
- android:gravity="center_vertical"
- app:tint="@color/default_icon_color_tint_list" />
-
- </LinearLayout>
-
- <View
- android:id="@+id/weblayer_menu_item_divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="@color/divider_line_bg_color"
- android:visibility="gone" />
-
-</LinearLayout>
-
diff --git a/chromium/weblayer/browser/java/res/values/dimens.xml b/chromium/weblayer/browser/java/res/values/dimens.xml
index 0eee3fc9758..30a1496801f 100644
--- a/chromium/weblayer/browser/java/res/values/dimens.xml
+++ b/chromium/weblayer/browser/java/res/values/dimens.xml
@@ -9,7 +9,6 @@
<!-- Dimensions for compact translate infobar. -->
<dimen name="weblayer_infobar_translate_fade_edge_length">18dp</dimen>
- <dimen name="weblayer_infobar_translate_menu_width">260dp</dimen>
<!-- Dimens of tab indicator -->
<dimen name="weblayer_tab_indicator_radius">3dp</dimen>
diff --git a/chromium/weblayer/browser/java/res/values/styles.xml b/chromium/weblayer/browser/java/res/values/styles.xml
index f362fd9ab69..ff8d17d2a84 100644
--- a/chromium/weblayer/browser/java/res/values/styles.xml
+++ b/chromium/weblayer/browser/java/res/values/styles.xml
@@ -8,15 +8,9 @@
<item name="spinnerStyle">@style/SpinnerStyle</item>
<item name="preferenceTheme">@style/PreferenceTheme</item>
<item name="alertDialogTheme">@style/Theme.Chromium.AlertDialog</item>
- </style>
-
- <!-- The following styles may be used to style views provided by a CustomViewBinder or attached
- to the app menu as headers or footers. -->
- <!-- Styling for an app menu item row. -->
- <style name="WebLayerAppMenuItem">
- <item name="android:paddingStart">16dp</item>
- <item name="android:paddingEnd">16dp</item>
- <item name="android:background">?attr/listChoiceBackgroundIndicator</item>
+ <!-- Text style attributes used by the preference_material.xml layout. -->
+ <item name="android:textAppearanceListItem">@style/TextAppearance.TextLarge.Primary</item>
+ <item name="android:textColorSecondary">@color/default_text_color_secondary_list</item>
</style>
</resources>
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_af.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_af.xtb
index 62d289ff62c..403610204ab 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_af.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_af.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="af">
-<translation id="1068672505746868501">Moet nooit bladsye in <ph name="SOURCE_LANGUAGE" /> vertaal nie</translation>
-<translation id="124116460088058876">Meer tale</translation>
-<translation id="1285320974508926690">Moet nooit hierdie werf vertaal nie</translation>
-<translation id="290376772003165898">Bladsy is nie in <ph name="LANGUAGE" /> nie?</translation>
-<translation id="5684874026226664614">Oeps. Hierdie bladsy kon nie vertaal word nie.</translation>
-<translation id="6040143037577758943">Maak toe</translation>
-<translation id="6831043979455480757">Vertaal</translation>
-<translation id="7243308994586599757">Opsies is naby die onderkant van die skerm beskikbaar</translation>
-<translation id="773466115871691567">Vertaal altyd bladsye in <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Webblaaieraktiwiteit</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_am.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_am.xtb
index ec9bad225cb..2fd6e46a16e 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_am.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_am.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="am">
-<translation id="1068672505746868501">በ<ph name="SOURCE_LANGUAGE" /> ውስጥ ገጾችን በጭራሽ አትተርጉም</translation>
-<translation id="124116460088058876">ተጨማሪ ቋንቋዎች</translation>
-<translation id="1285320974508926690">ይህን ጣቢያ በጭራሽ አትተርጉም</translation>
-<translation id="290376772003165898">ገጽ በ<ph name="LANGUAGE" /> አይደለም?</translation>
-<translation id="5684874026226664614">ውይ። ይህ ገጽ ሊተረጎም አይችልም።</translation>
-<translation id="6040143037577758943">ዝጋ</translation>
-<translation id="6831043979455480757">መተርጎም</translation>
-<translation id="7243308994586599757">አማራጮች ከማያ ገጹ ግርጌ አጠገብ ይገኛሉ</translation>
-<translation id="773466115871691567">ገጾችን ሁልጊዜ በ<ph name="SOURCE_LANGUAGE" /> ተርጉም</translation>
<translation id="8298278839890148234">የድር አሳሽ እንቅስቃሴ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ar.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ar.xtb
index b631d5aa80b..55fcefece9b 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ar.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ar.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ar">
-<translation id="1068672505746868501">عدم ترجمة الصفحات باللغة <ph name="SOURCE_LANGUAGE" /> مُطلقًا</translation>
-<translation id="124116460088058876">مزيد من اللغات</translation>
-<translation id="1285320974508926690">عدم ترجمة هذا الموقع مطلقًا</translation>
-<translation id="290376772003165898">أليست الصفحة باللغة <ph name="LANGUAGE" />؟</translation>
-<translation id="5684874026226664614">عفوًا. تعذرت ترجمة هذه الصفحة.</translation>
-<translation id="6040143037577758943">إغلاق</translation>
-<translation id="6831043979455480757">ترجمة</translation>
-<translation id="7243308994586599757">الخيارات المتاحة بالقرب من الجزء السفلي من الشاشة</translation>
-<translation id="773466115871691567">ترجمة الصفحات باللغة <ph name="SOURCE_LANGUAGE" /> دائمًا</translation>
<translation id="8298278839890148234">نشاط التصفُّح على الويب</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_as.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_as.xtb
index 409550b1d05..db63c417200 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_as.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_as.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="as">
-<translation id="1068672505746868501">পৃষ্ঠা <ph name="SOURCE_LANGUAGE" />লৈ কেতিয়াও অনুবাদ নকৰিব</translation>
-<translation id="124116460088058876">অধিক ভাষা</translation>
-<translation id="1285320974508926690">এই ছাইটটো কেতিয়াও অনুবাদ নকৰিব</translation>
-<translation id="290376772003165898">পৃষ্ঠাটো <ph name="LANGUAGE" /> ভাষাত নাই নেকি?</translation>
-<translation id="5684874026226664614">ওঁহ এই পৃষ্ঠাটো অনুবাদ কৰিব পৰা নগ’ল।</translation>
-<translation id="6040143037577758943">বন্ধ কৰক</translation>
-<translation id="6831043979455480757">অনুবাদ কৰক</translation>
-<translation id="7243308994586599757">স্ক্ৰীণৰ কাষৰ বুটামত উপলব্ধ বিকল্প</translation>
-<translation id="773466115871691567">সদায় পৃষ্ঠাসমূহ <ph name="SOURCE_LANGUAGE" />লৈ অনুবাদ কৰক</translation>
<translation id="8298278839890148234">ৱেব ব্ৰাউজাৰৰ কার্যকলাপ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_az.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_az.xtb
index cd8a4a44f50..684871cc3c3 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_az.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_az.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="az">
-<translation id="1068672505746868501">Heç vaxt <ph name="SOURCE_LANGUAGE" /> dilində olan səhifələri tərcümə etməyin</translation>
-<translation id="124116460088058876">Digər dillər</translation>
-<translation id="1285320974508926690">Bu saytı heç vaxt tərcümə etməyin</translation>
-<translation id="290376772003165898">Səhifə <ph name="LANGUAGE" /> dilində deyil?</translation>
-<translation id="5684874026226664614">Bu səhifə tərcümə edilə bilmir. Niyəsini bilmirik.</translation>
-<translation id="6040143037577758943">Qapat</translation>
-<translation id="6831043979455480757">Tərcümə et</translation>
-<translation id="7243308994586599757">Seçənəklər ekranın aşağısına yaxın yerdə əlçatandır</translation>
-<translation id="773466115871691567">Səhifələri həmişə <ph name="SOURCE_LANGUAGE" /> dilinə tərcümə edin</translation>
<translation id="8298278839890148234">Veb axtarış fəaliyyəti</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_be.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_be.xtb
index eff070e867a..4c18cf28a2f 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_be.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_be.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="be">
-<translation id="1068672505746868501">Ніколі не перакладаць старонкі на наступнай мове: <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Іншыя мовы</translation>
-<translation id="1285320974508926690">Ніколі не перакладаць гэты сайт</translation>
-<translation id="290376772003165898">Мова старонкі – не <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Памылка. Не ўдалося перакласці гэту старонку.</translation>
-<translation id="6040143037577758943">Закрыць</translation>
-<translation id="6831043979455480757">Перакласці</translation>
-<translation id="7243308994586599757">Параметры знаходзяцца ў ніжняй частцы экрана</translation>
-<translation id="773466115871691567">Заўсёды перакладаць старонкі на наступнай мове: <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Дзеянні ў вэб-браўзеры</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_bg.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_bg.xtb
index a55fe167dff..1e7789939c0 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_bg.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_bg.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bg">
-<translation id="1068672505746868501">Страниците на <ph name="SOURCE_LANGUAGE" /> да не се превеждат</translation>
-<translation id="124116460088058876">Още езици</translation>
-<translation id="1285320974508926690">Този сайт да не се превежда никога</translation>
-<translation id="290376772003165898">Страницата не е на <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Ами сега! Тази страница не можа да се преведе.</translation>
-<translation id="6040143037577758943">Затваряне</translation>
-<translation id="6831043979455480757">Превод</translation>
-<translation id="7243308994586599757">Опциите са в долната част на екрана</translation>
-<translation id="773466115871691567">Страниците на <ph name="SOURCE_LANGUAGE" /> да се превеждат винаги</translation>
<translation id="8298278839890148234">Активност в уеб браузъра</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_bn.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_bn.xtb
index 81f76d848f2..374b81798d7 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_bn.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_bn.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bn">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> ভাষার পৃষ্ঠার অনুবাদ কখনও দেখতে চাই না</translation>
-<translation id="124116460088058876">আরও ভাষা</translation>
-<translation id="1285320974508926690">কখনই এই সাইটটিকে অনুবাদ করবেন না</translation>
-<translation id="290376772003165898">পৃষ্ঠাটি <ph name="LANGUAGE" /> ভাষায় নয়?</translation>
-<translation id="5684874026226664614">ওহো৷ এই পৃষ্ঠাটির অনুবাদ করা যাবে না৷</translation>
-<translation id="6040143037577758943">বন্ধ</translation>
-<translation id="6831043979455480757">অনুবাদ</translation>
-<translation id="7243308994586599757">স্ক্রীনের প্রায় নীচের দিকে বিকল্পগুলি উপলব্ধ</translation>
-<translation id="773466115871691567">সব সময় <ph name="SOURCE_LANGUAGE" /> ভাষার পৃষ্ঠার অনুবাদ দেখতে চাই</translation>
<translation id="8298278839890148234">ওয়েব ব্রাউজার অ্যাক্টিভিটি</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_bs.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_bs.xtb
index 5d1aefcaea1..4fb2dbb390e 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_bs.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_bs.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bs">
-<translation id="1068672505746868501">Nemoj nikada prevoditi stranice na <ph name="SOURCE_LANGUAGE" /> jezik</translation>
-<translation id="124116460088058876">Više jezika</translation>
-<translation id="1285320974508926690">Nikada ne prevodi ovu web lokaciju</translation>
-<translation id="290376772003165898">Ovo nije <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Ups. Prijevod ove stranice nije uspio.</translation>
-<translation id="6040143037577758943">Zatvori</translation>
-<translation id="6831043979455480757">Prevedi</translation>
-<translation id="7243308994586599757">Opcije su dostupne pri dnu ekrana</translation>
-<translation id="773466115871691567">Uvijek prevedi stranice na <ph name="SOURCE_LANGUAGE" /> jezik</translation>
<translation id="8298278839890148234">Aktivnost web preglednika</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ca.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ca.xtb
index 3c181c2e235..ba2d4e4da24 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ca.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ca.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ca">
-<translation id="1068672505746868501">No tradueixis mai les pàgines en <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Més idiomes</translation>
-<translation id="1285320974508926690">No tradueixis mai aquest lloc</translation>
-<translation id="290376772003165898">La pàgina no està en <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Aquesta pàgina no s'ha pogut traduir.</translation>
-<translation id="6040143037577758943">Tanca</translation>
-<translation id="6831043979455480757">Tradueix</translation>
-<translation id="7243308994586599757">Opcions disponibles a la part inferior de la pantalla</translation>
-<translation id="773466115871691567">Tradueix sempre les pàgines en <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Activitat del navegador web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_cs.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_cs.xtb
index 7e7b91a9744..5710c42229a 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_cs.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_cs.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="cs">
-<translation id="1068672505746868501">Stránky v jazyce <ph name="SOURCE_LANGUAGE" /> nikdy nepřekládat</translation>
-<translation id="124116460088058876">Další jazyky</translation>
-<translation id="1285320974508926690">Tento web nikdy nepřekládat</translation>
-<translation id="290376772003165898">Stránka není v jazyce <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Jejda. Tuto stránku se nepodařilo přeložit.</translation>
-<translation id="6040143037577758943">Zavřít</translation>
-<translation id="6831043979455480757">Přeložit</translation>
-<translation id="7243308994586599757">Možnosti jsou k dispozici ve spodní části obrazovky</translation>
-<translation id="773466115871691567">Stránky v jazyce <ph name="SOURCE_LANGUAGE" /> vždy překládat</translation>
<translation id="8298278839890148234">Aktivita ve webovém prohlížeči</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_da.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_da.xtb
index 571f36b83ac..63df7f53aa1 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_da.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_da.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="da">
-<translation id="1068672505746868501">Oversæt aldrig sider på <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Flere sprog</translation>
-<translation id="1285320974508926690">Oversæt aldrig dette website</translation>
-<translation id="290376772003165898">Er siden ikke på <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Ups! Denne side kunne ikke oversættes.</translation>
-<translation id="6040143037577758943">Luk</translation>
-<translation id="6831043979455480757">Oversæt</translation>
-<translation id="7243308994586599757">Du finder indstillingerne nederst på skærmen</translation>
-<translation id="773466115871691567">Oversæt altid sider på <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Webbrowseraktivitet</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_de.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_de.xtb
index 65cd87c466a..a6c724e09b6 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_de.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_de.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="de">
-<translation id="1068672505746868501">Seiten auf <ph name="SOURCE_LANGUAGE" /> nie übersetzen</translation>
-<translation id="124116460088058876">Weitere Sprachen</translation>
-<translation id="1285320974508926690">Diese Website nie übersetzen</translation>
-<translation id="290376772003165898">Diese Seite ist nicht auf <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Hoppla! Diese Seite konnte nicht übersetzt werden.</translation>
-<translation id="6040143037577758943">Schließen</translation>
-<translation id="6831043979455480757">Übersetzen</translation>
-<translation id="7243308994586599757">Optionen unten auf dem Bildschirm verfügbar</translation>
-<translation id="773466115871691567">Seiten auf <ph name="SOURCE_LANGUAGE" /> immer übersetzen</translation>
<translation id="8298278839890148234">Webbrowseraktivitäten</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_el.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_el.xtb
index 1e22b4a980c..91f7efb7d08 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_el.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_el.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="el">
-<translation id="1068672505746868501">Να μην γίνεται μετάφραση σελίδων στα <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Περισσότερες γλώσσες</translation>
-<translation id="1285320974508926690">Να μην γίνεται ποτέ μετάφραση αυτού του ιστότοπου</translation>
-<translation id="290376772003165898">Η σελίδα δεν είναι στα <ph name="LANGUAGE" />;</translation>
-<translation id="5684874026226664614">Ωχ. Δεν ήταν δυνατή η μετάφραση αυτής της σελίδας.</translation>
-<translation id="6040143037577758943">Κλείσιμο</translation>
-<translation id="6831043979455480757">Μετάφραση</translation>
-<translation id="7243308994586599757">Διαθέσιμες επιλογές κοντά κάτω μέρος της οθόνης</translation>
-<translation id="773466115871691567">Να μεταφράζονται πάντα οι σελίδες προς τα <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Δραστηριότητα προγράμματος περιήγησης στον ιστό</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_en-GB.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_en-GB.xtb
index 8f63e62c0db..078cecbe647 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_en-GB.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_en-GB.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="en-GB">
-<translation id="1068672505746868501">Never translate pages in <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">More languages</translation>
-<translation id="1285320974508926690">Never translate this site</translation>
-<translation id="290376772003165898">Page is not in <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Oops. This page could not be translated.</translation>
-<translation id="6040143037577758943">Close</translation>
-<translation id="6831043979455480757">Translate</translation>
-<translation id="7243308994586599757">Options available near bottom of the screen</translation>
-<translation id="773466115871691567">Always translate pages in <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Web browser activity</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_es-419.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_es-419.xtb
index 276fe173c58..e529fa34f49 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_es-419.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_es-419.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="es-419">
-<translation id="1068672505746868501">No traducir nunca páginas en <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Más idiomas</translation>
-<translation id="1285320974508926690">Nunca traducir este sitio</translation>
-<translation id="290376772003165898">¿La página no está en <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">No se puede traducir esta página.</translation>
-<translation id="6040143037577758943">Cerrar</translation>
-<translation id="6831043979455480757">Traducir</translation>
-<translation id="7243308994586599757">Opciones disponibles junto a la parte inferior de la pantalla</translation>
-<translation id="773466115871691567">Traducir siempre las páginas en <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Actividad del navegador web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_es.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_es.xtb
index 8b61d2a834e..fcf6da55978 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_es.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_es.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="es">
-<translation id="1068672505746868501">No traducir nunca las páginas en <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Más idiomas</translation>
-<translation id="1285320974508926690">No traducir nunca este sitio</translation>
-<translation id="290376772003165898">¿La página no está en <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">¡Vaya! No se ha podido traducir esta página.</translation>
-<translation id="6040143037577758943">Cerrar</translation>
-<translation id="6831043979455480757">Traducir</translation>
-<translation id="7243308994586599757">Opciones disponibles cerca de la parte inferior de la pantalla</translation>
-<translation id="773466115871691567">Traducir siempre las páginas en <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Actividad del navegador web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_et.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_et.xtb
index ff14c3ea03e..37ada0e9df4 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_et.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_et.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="et">
-<translation id="1068672505746868501">Ära tõlgi kunagi <ph name="SOURCE_LANGUAGE" /> keeles olevaid lehti</translation>
-<translation id="124116460088058876">Rohkem keeli</translation>
-<translation id="1285320974508926690">Ära kunagi seda saiti tõlgi</translation>
-<translation id="290376772003165898">Kas leht ei ole <ph name="LANGUAGE" /> keeles?</translation>
-<translation id="5684874026226664614">Vabandust. Lehte ei õnnestunud tõlkida.</translation>
-<translation id="6040143037577758943">Sulge</translation>
-<translation id="6831043979455480757">Tõlgi</translation>
-<translation id="7243308994586599757">Valikud on saadaval ekraani allosas</translation>
-<translation id="773466115871691567">Tõlgi alati <ph name="SOURCE_LANGUAGE" /> keeles olevad lehed</translation>
<translation id="8298278839890148234">Veebibrauseri tegevused</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_eu.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_eu.xtb
index 0fe579c1cb0..2698f9fb351 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_eu.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_eu.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="eu">
-<translation id="1068672505746868501">Ez itzuli inoiz <ph name="SOURCE_LANGUAGE" /> darabilten orriak</translation>
-<translation id="124116460088058876">Hizkuntza gehiago</translation>
-<translation id="1285320974508926690">Ez itzuli inoiz webgune hau</translation>
-<translation id="290376772003165898">Ez al da <ph name="LANGUAGE" /> orriko hizkuntza?</translation>
-<translation id="5684874026226664614">Ezin izan da orria itzuli.</translation>
-<translation id="6040143037577758943">Itxi</translation>
-<translation id="6831043979455480757">Itzuli</translation>
-<translation id="7243308994586599757">Pantailaren behealdean agertzen dira dauden aukerak</translation>
-<translation id="773466115871691567">Itzuli beti <ph name="SOURCE_LANGUAGE" /> darabilten orriak</translation>
<translation id="8298278839890148234">Sareko arakatze-jarduerak</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_fa.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_fa.xtb
index b3cf59018eb..77daea83d86 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_fa.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_fa.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fa">
-<translation id="1068672505746868501">هرگز صفحه‌های <ph name="SOURCE_LANGUAGE" /> ترجمه نشوند</translation>
-<translation id="124116460088058876">زبان‌های بیشتر</translation>
-<translation id="1285320974508926690">این سایت هرگز ترجمه نشود</translation>
-<translation id="290376772003165898">صفحه به زبان <ph name="LANGUAGE" /> وجود ندارد؟</translation>
-<translation id="5684874026226664614">متأسفیم. این صفحه ترجمه نشد.</translation>
-<translation id="6040143037577758943">بستن</translation>
-<translation id="6831043979455480757">ترجمه</translation>
-<translation id="7243308994586599757">گزینه‌ها در نزدیک پایین صفحه نمایش در دسترس هستند</translation>
-<translation id="773466115871691567">صفحه‌های <ph name="SOURCE_LANGUAGE" /> همیشه ترجمه شوند</translation>
<translation id="8298278839890148234">فعالیت مرورگر وب</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_fi.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_fi.xtb
index e8e035371e0..78a8d793d2e 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_fi.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_fi.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fi">
-<translation id="1068672505746868501">Älä koskaan käännä kielellä <ph name="SOURCE_LANGUAGE" /> kirjoitettuja sivuja.</translation>
-<translation id="124116460088058876">Lisää kieliä</translation>
-<translation id="1285320974508926690">Älä käännä tätä sivustoa</translation>
-<translation id="290376772003165898">Eikö sivu ole kirjoitettu kielellä <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Hups, tätä sivua ei voi kääntää.</translation>
-<translation id="6040143037577758943">Sulje</translation>
-<translation id="6831043979455480757">Käännä</translation>
-<translation id="7243308994586599757">Asetukset löytyvät näytön alalaidasta.</translation>
-<translation id="773466115871691567">Käännä aina kielellä <ph name="SOURCE_LANGUAGE" /> kirjoitut sivut</translation>
<translation id="8298278839890148234">Verkon selaustoiminta</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_fil.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_fil.xtb
index 01ddf5eb7ec..08f97ffffd4 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_fil.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_fil.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fil">
-<translation id="1068672505746868501">Huwag kailanman isalin ang mga page sa <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Higit pang wika</translation>
-<translation id="1285320974508926690">Huwag isalin kailanman ang site na ito</translation>
-<translation id="290376772003165898">Hindi nakasalin ang page sa <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Oops. Hindi maisalin ang pahinang ito.</translation>
-<translation id="6040143037577758943">Isara</translation>
-<translation id="6831043979455480757">Isalin</translation>
-<translation id="7243308994586599757">May mga opsyon malapit sa ibaba ng screen</translation>
-<translation id="773466115871691567">Palaging isalin ang mga page sa <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Aktibidad ng web browser</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_fr-CA.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_fr-CA.xtb
index 2415250b42a..537978cc551 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_fr-CA.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_fr-CA.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fr-CA">
-<translation id="1068672505746868501">Ne jamais traduire les pages en <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Plus de langues</translation>
-<translation id="1285320974508926690">Ne jamais traduire ce site</translation>
-<translation id="290376772003165898">Cette page n'est pas en <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Oups… Impossible de traduire cette page.</translation>
-<translation id="6040143037577758943">Fermer</translation>
-<translation id="6831043979455480757">Traduire</translation>
-<translation id="7243308994586599757">Options disponibles vers le bas de l’écran</translation>
-<translation id="773466115871691567">Toujours traduire les pages en <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Activité de navigation Web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_fr.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_fr.xtb
index 334bf0344fd..9810a3e323a 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_fr.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_fr.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fr">
-<translation id="1068672505746868501">Ne jamais traduire les pages en <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Plus de langues</translation>
-<translation id="1285320974508926690">Ne jamais traduire ce site</translation>
-<translation id="290376772003165898">La page n'est pas en <ph name="LANGUAGE" /> ?</translation>
-<translation id="5684874026226664614">Petit problème… Impossible de traduire cette page.</translation>
-<translation id="6040143037577758943">Fermer</translation>
-<translation id="6831043979455480757">Traduire</translation>
-<translation id="7243308994586599757">Options disponibles au bas de l'écran</translation>
-<translation id="773466115871691567">Toujours traduire les pages en <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Activité de navigation sur le Web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_gl.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_gl.xtb
index 3f598e52c3b..c315bcbcd56 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_gl.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_gl.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="gl">
-<translation id="1068672505746868501">Non traducir nunca páxinas en <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Máis idiomas</translation>
-<translation id="1285320974508926690">Non traducir nunca este sitio</translation>
-<translation id="290376772003165898">A páxina non está en <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Non se puido traducir esta páxina.</translation>
-<translation id="6040143037577758943">Pechar</translation>
-<translation id="6831043979455480757">Traducir</translation>
-<translation id="7243308994586599757">Opcións dispoñibles na parte inferior da pantalla</translation>
-<translation id="773466115871691567">Traducir sempre páxinas en <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Actividade de navegación pola Web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_gu.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_gu.xtb
index 957cc2993a6..9e2ee22696d 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_gu.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_gu.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="gu">
-<translation id="1068672505746868501">પેજનો ક્યારેય પણ <ph name="SOURCE_LANGUAGE" />માં અનુવાદ કરશો નહીં</translation>
-<translation id="124116460088058876">વધુ ભાષાઓ</translation>
-<translation id="1285320974508926690">આ સાઇટનું ક્યારેય ભાષાંતર કરશો નહીં</translation>
-<translation id="290376772003165898">પેજ <ph name="LANGUAGE" />માં નથી?</translation>
-<translation id="5684874026226664614">અરેરે. આ પૃષ્ઠનો અનુવાદ કરી શકાયો નથી.</translation>
-<translation id="6040143037577758943">બંધ કરો</translation>
-<translation id="6831043979455480757">અનુવાદ કરો</translation>
-<translation id="7243308994586599757">સ્ક્રીનના તળિયા નજીક વિકલ્પો ઉપલબ્ધ છે</translation>
-<translation id="773466115871691567">હંમેશાં પેજનો <ph name="SOURCE_LANGUAGE" />માં અનુવાદ કરો</translation>
<translation id="8298278839890148234">વેબ બ્રાઉઝરની પ્રવૃત્તિ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_hi.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_hi.xtb
index 6fe2057217c..a9ae0e70db1 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_hi.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_hi.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hi">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> भाषा के पेज का कभी भी अनुवाद न करें</translation>
-<translation id="124116460088058876">ज़्यादा भाषाएं</translation>
-<translation id="1285320974508926690">कभी भी इस साइट का अनुवाद न करें</translation>
-<translation id="290376772003165898">क्या पेज <ph name="LANGUAGE" /> भाषा में नहीं है?</translation>
-<translation id="5684874026226664614">ओह. इस पेज का अनुवाद नहीं किया जा सका.</translation>
-<translation id="6040143037577758943">बंद करें</translation>
-<translation id="6831043979455480757">अनुवाद करें</translation>
-<translation id="7243308994586599757">विकल्‍प स्‍क्रीन के नीचे उपलब्‍ध हैं</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> भाषा के पेज का हमेशा अनुवाद करें</translation>
<translation id="8298278839890148234">वेब ब्राउज़र की गतिविधि</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_hr.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_hr.xtb
index d9fc4ee6cec..bc0817b9c82 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_hr.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_hr.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hr">
-<translation id="1068672505746868501">Nikad ne prevodi <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Više jezika</translation>
-<translation id="1285320974508926690">Nikad nemoj prevoditi ovu web-lokaciju</translation>
-<translation id="290376772003165898">Ovo nije <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Ups. Stranicu nije bilo moguće prevesti.</translation>
-<translation id="6040143037577758943">Zatvori</translation>
-<translation id="6831043979455480757">Prevedi</translation>
-<translation id="7243308994586599757">Opcije dostupne pri dnu zaslona</translation>
-<translation id="773466115871691567">Uvijek prevodi <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Aktivnost u web-pregledniku</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_hu.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_hu.xtb
index 498d74cc4c9..587b17fb1f5 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_hu.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_hu.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hu">
-<translation id="1068672505746868501">Soha ne fordítsa le a(z) <ph name="SOURCE_LANGUAGE" /> nyelvű oldalakat</translation>
-<translation id="124116460088058876">További nyelvek…</translation>
-<translation id="1285320974508926690">Ezt a webhelyet soha ne fordítsa le</translation>
-<translation id="290376772003165898">Az oldal nem <ph name="LANGUAGE" /> nyelvű?</translation>
-<translation id="5684874026226664614">Hoppá! Az oldalt nem sikerült lefordítani.</translation>
-<translation id="6040143037577758943">Bezárás</translation>
-<translation id="6831043979455480757">Fordítás</translation>
-<translation id="7243308994586599757">A beállítások a képernyő alsó részén találhatók</translation>
-<translation id="773466115871691567">Mindig fordítsa le a(z) <ph name="SOURCE_LANGUAGE" /> nyelvű oldalakat</translation>
<translation id="8298278839890148234">Böngészős tevékenységek</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_hy.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_hy.xtb
index e3c1efcec5e..c5676da7cb3 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_hy.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_hy.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hy">
-<translation id="1068672505746868501">Երբեք չթարգմանել <ph name="SOURCE_LANGUAGE" /> էջերը</translation>
-<translation id="124116460088058876">Այլ լեզուներ</translation>
-<translation id="1285320974508926690">Երբեք չթարգմանել այս կայքը</translation>
-<translation id="290376772003165898">Էջը <ph name="LANGUAGE" /> չէ՞</translation>
-<translation id="5684874026226664614">Չհաջողվեց թարգմանել այս էջը:</translation>
-<translation id="6040143037577758943">Փակել</translation>
-<translation id="6831043979455480757">Թարգմանել</translation>
-<translation id="7243308994586599757">Ընտրանքները հասանելի են էկրանի ստորին հատվածում</translation>
-<translation id="773466115871691567">Միշտ թարգմանել <ph name="SOURCE_LANGUAGE" /> էջերը</translation>
<translation id="8298278839890148234">Գործողություններ դիտարկիչում</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_id.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_id.xtb
index 673f32be14c..31b5fe5d797 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_id.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_id.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="id">
-<translation id="1068672505746868501">Jangan pernah menerjemahkan halaman dalam <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Bahasa lainnya</translation>
-<translation id="1285320974508926690">Jangan pernah terjemahkan situs ini</translation>
-<translation id="290376772003165898">Halaman tidak dalam bahasa <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Ups. Halaman ini tidak dapat diterjemahkan.</translation>
-<translation id="6040143037577758943">Tutup</translation>
-<translation id="6831043979455480757">Terjemahkan</translation>
-<translation id="7243308994586599757">Opsi terdapat di dekat bagian bawah layar</translation>
-<translation id="773466115871691567">Selalu terjemahkan halaman dalam bahasa <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Aktivitas penjelajahan web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_is.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_is.xtb
index 2f77ab69860..923602bb298 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_is.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_is.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="is">
-<translation id="1068672505746868501">Þýða aldrei síður á þessu tungumáli: <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Fleiri tungumál</translation>
-<translation id="1285320974508926690">Aldrei þýða þetta vefsvæði</translation>
-<translation id="290376772003165898">Er tungumál síðunnar ekki <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Úbbs. Þessa síðu er ekki hægt að þýða.</translation>
-<translation id="6040143037577758943">Loka</translation>
-<translation id="6831043979455480757">Þýða</translation>
-<translation id="7243308994586599757">Valkostir eru neðst á skjánum</translation>
-<translation id="773466115871691567">Þýða alltaf síður á þessu tungumáli: <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Vafranotkun</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_it.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_it.xtb
index 1f19226503d..c4dc6e6ca5d 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_it.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_it.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="it">
-<translation id="1068672505746868501">Non tradurre mai le pagine in <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Altre lingue</translation>
-<translation id="1285320974508926690">Non tradurre mai questo sito</translation>
-<translation id="290376772003165898">La pagina non è in <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Spiacenti. Impossibile tradurre questa pagina.</translation>
-<translation id="6040143037577758943">Chiudi</translation>
-<translation id="6831043979455480757">Traduci</translation>
-<translation id="7243308994586599757">Opzioni disponibili nella parte inferiore dello schermo</translation>
-<translation id="773466115871691567">Traduci sempre le pagine in <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Attività del browser web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_iw.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_iw.xtb
index 61e44631e2e..bea498feca7 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_iw.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_iw.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="iw">
-<translation id="1068672505746868501">אף פעם אל תתרגם דפים ב<ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">שפות נוספות</translation>
-<translation id="1285320974508926690">איני רוצה לקבל תרגום של אתר זה</translation>
-<translation id="290376772003165898">הדף לא ב<ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">אופס. לא ניתן היה לתרגם את הדף הזה.</translation>
-<translation id="6040143037577758943">סגור</translation>
-<translation id="6831043979455480757">תרגום</translation>
-<translation id="7243308994586599757">אפשרויות הזמינות באזור החלק התחתון של המסך</translation>
-<translation id="773466115871691567">ברצוני לקבל תרגום תמיד דפים ב<ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">פעילות דפדפן אינטרנט</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ja.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ja.xtb
index cf3a9d91955..091fdcc87ff 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ja.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ja.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ja">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" />のページを翻訳しない</translation>
-<translation id="124116460088058876">その他の言語</translation>
-<translation id="1285320974508926690">このサイトは翻訳しない</translation>
-<translation id="290376772003165898"><ph name="LANGUAGE" />のページではない場合</translation>
-<translation id="5684874026226664614">このページを翻訳できませんでした。</translation>
-<translation id="6040143037577758943">閉じる</translation>
-<translation id="6831043979455480757">翻訳</translation>
-<translation id="7243308994586599757">画面の下の方にオプションがあります</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" />のページを常に翻訳する</translation>
<translation id="8298278839890148234">ウェブブラウザのアクティビティ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ka.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ka.xtb
index 2aa6a13f2ff..57bc785af7f 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ka.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ka.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ka">
-<translation id="1068672505746868501">არასოდეს ითარგმნოს <ph name="SOURCE_LANGUAGE" /> გვერდები</translation>
-<translation id="124116460088058876">სხვა ენები</translation>
-<translation id="1285320974508926690">არასდროს გადათარგმნო ეს საიტი</translation>
-<translation id="290376772003165898">გვერდის ტექსტი არ არის <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">ამ გვერდის გადათარგმნა ვერ მოხერხდა.</translation>
-<translation id="6040143037577758943">დახურვა</translation>
-<translation id="6831043979455480757">თარგმნა</translation>
-<translation id="7243308994586599757">ვარიანტები ხელმისაწვდომია ეკრანის ქვედა ნაწილთან</translation>
-<translation id="773466115871691567">ყოველთვის ითარგმნოს <ph name="SOURCE_LANGUAGE" /> გვერდები</translation>
<translation id="8298278839890148234">ვებ-ბრაუზერის აქტივობა</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_kk.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_kk.xtb
index 2e23049928a..d18117e9c7f 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_kk.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_kk.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="kk">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> тіліндегі беттер ешқашан аударылмасын</translation>
-<translation id="124116460088058876">Қосымша тілдер</translation>
-<translation id="1285320974508926690">Бұл сайтты ешқашан аудармау</translation>
-<translation id="290376772003165898">Бет <ph name="LANGUAGE" /> тілінде емес пе?</translation>
-<translation id="5684874026226664614">Бұл бетті аудару мүмкін емес.</translation>
-<translation id="6040143037577758943">Жабу</translation>
-<translation id="6831043979455480757">Аудару</translation>
-<translation id="7243308994586599757">Опциялар экранның төменгі жағында тұрады</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> тіліндегі беттер әрқашан аударылсын</translation>
<translation id="8298278839890148234">Браузерді қолдану мәліметі</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_km.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_km.xtb
index 79e7f51cb82..312955fb520 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_km.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_km.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="km">
-<translation id="1068672505746868501">កុំ​បកប្រែ​ទំព័រ​ជាភាសា <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">ភាសា​ច្រើន​ទៀត</translation>
-<translation id="1285320974508926690">មិនបកប្រែគេហទំព័រនេះទៀតឡើយ</translation>
-<translation id="290376772003165898">ទំព័រមិនមានជាភាសា <ph name="LANGUAGE" /> ទេ?</translation>
-<translation id="5684874026226664614">អូ។ ទំព័រនេះមិនអាចបកប្រែទេ។</translation>
-<translation id="6040143037577758943">បិទ</translation>
-<translation id="6831043979455480757">បកប្រែ</translation>
-<translation id="7243308994586599757">មានជម្រើសនៅក្បែរផ្នែកខាងក្រោមអេក្រង់</translation>
-<translation id="773466115871691567">បកប្រែ​ទំព័រ​ជាភាសា <ph name="SOURCE_LANGUAGE" /> ជានិច្ច</translation>
<translation id="8298278839890148234">សកម្មភាព​កម្មវិធីរុករក​តាមអ៊ីនធឺណិត</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_kn.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_kn.xtb
index cabf85f2d68..91524cd5c0f 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_kn.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_kn.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="kn">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> ನಲ್ಲಿನ ಪುಟಗಳನ್ನು ಎಂದಿಗೂ ಅನುವಾದ ಮಾಡಬೇಡಿ</translation>
-<translation id="124116460088058876">ಹೆಚ್ಚಿನ ಭಾಷೆಗಳು</translation>
-<translation id="1285320974508926690">ಈ ಸೈಟ್ ಅನ್ನು ಎಂದಿಗೂ ಭಾಷಾಂತರಿಸದಿರಿ</translation>
-<translation id="290376772003165898"><ph name="LANGUAGE" /> ನಲ್ಲಿನ ಪುಟ ಇಲ್ಲವೇ?</translation>
-<translation id="5684874026226664614">ಓಹ್. ಈ ಪುಟವನ್ನು ಅನುವಾದಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
-<translation id="6040143037577758943">ಮುಚ್ಚಿರಿ</translation>
-<translation id="6831043979455480757">ಅನುವಾದಿಸು</translation>
-<translation id="7243308994586599757">ಪರದೆಯ ಕೆಳಗೆ ಲಭ್ಯವಿರುವ ಆಯ್ಕೆಗಳು</translation>
-<translation id="773466115871691567">ಯಾವಾಗಲು <ph name="SOURCE_LANGUAGE" /> ನಲ್ಲಿನ ಪುಟಗಳನ್ನು ಅನುವಾದ ಮಾಡಿ</translation>
<translation id="8298278839890148234">ವೆಬ್ ಬ್ರೌಸಿಂಗ್ ಚಟುವಟಿಕೆ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ko.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ko.xtb
index de20f5dc367..742a5338444 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ko.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ko.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ko">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" />로 된 페이지는 번역하지 않음</translation>
-<translation id="124116460088058876">다른 언어</translation>
-<translation id="1285320974508926690">이 사이트 번역 안함</translation>
-<translation id="290376772003165898">페이지 언어가 <ph name="LANGUAGE" />가 아닌가요?</translation>
-<translation id="5684874026226664614">죄송합니다. 이 페이지를 번역할 수 없습니다.</translation>
-<translation id="6040143037577758943">닫기</translation>
-<translation id="6831043979455480757">번역</translation>
-<translation id="7243308994586599757">화면 하단에서 옵션 선택 가능</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" />로 된 페이지를 항상 번역</translation>
<translation id="8298278839890148234">웹브라우저 활동</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ky.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ky.xtb
index 717031affb9..2d0f4b479b2 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ky.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ky.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ky">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> тилиндеги барактар эч качан которулбасын</translation>
-<translation id="124116460088058876">Дагы тилдер</translation>
-<translation id="1285320974508926690">Бул сайт эч качан которулбасын</translation>
-<translation id="290376772003165898">Барак <ph name="LANGUAGE" /> тилинде эмес бекен?</translation>
-<translation id="5684874026226664614">Ой, бул бет которулган жок.</translation>
-<translation id="6040143037577758943">Жабуу</translation>
-<translation id="6831043979455480757">Которуу</translation>
-<translation id="7243308994586599757">Параметрлер экрандын түбүндө берилген</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> тилиндеги барактар дайыма которулсун</translation>
<translation id="8298278839890148234">Көрүлгөн вебсайттар</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_lo.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_lo.xtb
index 7ab378b6803..fba8f18695e 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_lo.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_lo.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lo">
-<translation id="1068672505746868501">ຢ່າແປໜ້າຕ່າງໆໃນ <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">ພາສາເພີ່ມເຕີມ</translation>
-<translation id="1285320974508926690">ຢ່າແປເວັບ​ໄຊ​ທ໌ນີ້</translation>
-<translation id="290376772003165898">ໜ້າບໍ່ຢູ່ໃນ <ph name="LANGUAGE" /> ບໍ?</translation>
-<translation id="5684874026226664614">ອຸ້ຍ. ບໍ່ສາມາດແປໜ້ານີ້ໄດ້.</translation>
-<translation id="6040143037577758943">ປິດ</translation>
-<translation id="6831043979455480757">ແປພາສາ</translation>
-<translation id="7243308994586599757">ທາງ​ເລືອກ​ມີ​ໃຫ້​ໃກ້​ປຸ່ມ​ຂອງ​ໜ້າ​ຈໍ</translation>
-<translation id="773466115871691567">ແປໜ້າຕ່າງໆສະເໝີໃນ <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">ການເຄື່ອນໄຫວໃນໂປຣແກຣມທ່ອງເວັບ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_lt.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_lt.xtb
index 05d3d0706ff..a1a90e6ff7c 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_lt.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_lt.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lt">
-<translation id="1068672505746868501">Niekada neversti puslapių, parašytų <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Daugiau kalbų</translation>
-<translation id="1285320974508926690">Niekada neversti šios svetainės</translation>
-<translation id="290376772003165898">Puslapis parašytas ne <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Oi, nepavyko išversti šio puslapio.</translation>
-<translation id="6040143037577758943">Uždaryti</translation>
-<translation id="6831043979455480757">Vertėjas</translation>
-<translation id="7243308994586599757">Parinktys pasiekiamos netoli ekrano apačios</translation>
-<translation id="773466115871691567">Visada versti puslapius, parašytus <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Žiniatinklio naršyklės veikla</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_lv.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_lv.xtb
index d53de48768c..5d965478866 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_lv.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_lv.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lv">
-<translation id="1068672505746868501">Nekad netulkot lapas šādā valodā: <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Citas valodas…</translation>
-<translation id="1285320974508926690">Nekad netulkot šo vietni</translation>
-<translation id="290376772003165898">Vai lapa nav šajā valodā: <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Hmm... Šo lapu nevarēja iztulkot.</translation>
-<translation id="6040143037577758943">Aizvērt</translation>
-<translation id="6831043979455480757">Tulkot</translation>
-<translation id="7243308994586599757">Opcijas, kas pieejamas ekrāna apakšējā daļā</translation>
-<translation id="773466115871691567">Vienmēr tulkot lapas šādā valodā: <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Pārlūkošanas darbības</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_mk.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_mk.xtb
index 82359fc6539..2f2d3c2b91b 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_mk.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_mk.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="mk">
-<translation id="1068672505746868501">Никогаш не преведувај страници на <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Повеќе јазици</translation>
-<translation id="1285320974508926690">Никогаш не преведувај ја оваа локација</translation>
-<translation id="290376772003165898">Страницата не е на <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Оваа страница не може да се преведе.</translation>
-<translation id="6040143037577758943">Затвори</translation>
-<translation id="6831043979455480757">Преведи</translation>
-<translation id="7243308994586599757">Достапни се опции на дното на екранот</translation>
-<translation id="773466115871691567">Секогаш преведувај ги страниците на <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Активност на прелистувачот</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ml.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ml.xtb
index 8d51f41f713..d4a01802579 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ml.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ml.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ml">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> ഭാഷയിലുള്ള പേജുകൾ ഒരിക്കലും വിവർത്തനം ചെയ്യരുത്</translation>
-<translation id="124116460088058876">കൂടുതൽ ഭാഷകൾ</translation>
-<translation id="1285320974508926690">ഈ സൈറ്റ് ഒരിക്കലും വിവര്‍‌ത്തനം ചെയ്യരുത്</translation>
-<translation id="290376772003165898">പേജ് <ph name="LANGUAGE" /> ഭാഷയിലല്ലേ?</translation>
-<translation id="5684874026226664614">ക്ഷമിക്കണം. ഈ പേജ് വിവർത്തനം ചെയ്യാനായില്ല.</translation>
-<translation id="6040143037577758943">അടയ്ക്കുക</translation>
-<translation id="6831043979455480757">വിവർത്തനം ചെയ്യുക</translation>
-<translation id="7243308994586599757">സ്‌ക്രീനിന്റെ ചുവടെ ഓപ്‌ഷനുകൾ ലഭ്യമാണ്</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> ഭാഷയിലുള്ള പേജുകൾ എപ്പോഴും വിവർത്തനം ചെയ്യുക</translation>
<translation id="8298278839890148234">വെബ് ബ്രൗസർ ആക്റ്റിവിറ്റി</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_mn.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_mn.xtb
index 2f721cf0b56..79d5dac7607 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_mn.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_mn.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="mn">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> хэл дээрх хуудсыг хэзээ ч орчуулахгүй</translation>
-<translation id="124116460088058876">Бусад хэл</translation>
-<translation id="1285320974508926690">Энэ сайтыг хэзээ ч бүү хөрвүүл</translation>
-<translation id="290376772003165898">Хуудас <ph name="LANGUAGE" /> хэл дээр биш байна уу?</translation>
-<translation id="5684874026226664614">Өө. Энэ хуудсыг хөрвүүлж чадсангүй.</translation>
-<translation id="6040143037577758943">Хаах</translation>
-<translation id="6831043979455480757">Хөрвүүлэх</translation>
-<translation id="7243308994586599757">Дэлгэцийн доод хэсэгт сонголт боломжтой</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> хэл дээрх хуудсыг байнга орчуулна</translation>
<translation id="8298278839890148234">Хөтчийн үйл ажиллагаа</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_mr.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_mr.xtb
index 66b36082e3d..5a3e6820752 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_mr.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_mr.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="mr">
-<translation id="1068672505746868501">पेज <ph name="SOURCE_LANGUAGE" /> मध्ये कधीही भाषांतरित करू नका</translation>
-<translation id="124116460088058876">आणखी भाषा...</translation>
-<translation id="1285320974508926690">या साइटचा कधीही भाषांतर करु नका</translation>
-<translation id="290376772003165898">पेज <ph name="LANGUAGE" />मध्ये नाही?</translation>
-<translation id="5684874026226664614">अरेरे. हे पृष्‍ठ भाषांतरित केले जाऊ शकले नाही.</translation>
-<translation id="6040143037577758943">बंद करा</translation>
-<translation id="6831043979455480757">भाषांतर करा</translation>
-<translation id="7243308994586599757">स्क्रीनच्या तळाशी पर्याय उपलब्ध आहेत</translation>
-<translation id="773466115871691567">नेहमी पेज <ph name="SOURCE_LANGUAGE" />मध्ये भाषांतरित करा</translation>
<translation id="8298278839890148234">वेब ब्राउझर अ‍ॅक्टिव्हिटी</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ms.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ms.xtb
index 9bca4a8918a..e105952bce6 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ms.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ms.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ms">
-<translation id="1068672505746868501">Jangan sekali-kali terjemahkan halaman dalam <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Lagi bahasa</translation>
-<translation id="1285320974508926690">Jangan sekali-kali menterjemahkan tapak ini</translation>
-<translation id="290376772003165898">Halaman bukan dalam <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Op. Halaman ini tidak dapat diterjemahkan.</translation>
-<translation id="6040143037577758943">Tutup</translation>
-<translation id="6831043979455480757">Terjemah</translation>
-<translation id="7243308994586599757">Pilihan tersedia berhampiran bahagian bawah skrin</translation>
-<translation id="773466115871691567">Sentiasa terjemahkan halaman dalam <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Aktiviti penyemakan imbas</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_my.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_my.xtb
index ed292bfc27e..e8bf710e16c 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_my.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_my.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="my">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> ဘာသာ စာမျက်နှာများကို ဘယ်သောအခါမျှ ဘာသာမပြန်ရန်</translation>
-<translation id="124116460088058876">နောက်ထပ် ဘာသာစကားများ</translation>
-<translation id="1285320974508926690">ဒီဆိုက်ကို ဘယ်တော့မှ ဘာသာမပြန်ပါနှင့်</translation>
-<translation id="290376772003165898">စာမျက်နှာသည် <ph name="LANGUAGE" /> ဖြင့် ဟုတ်ပါသလား။</translation>
-<translation id="5684874026226664614">အူးပ်စ်။ ဒီစာမျက်နှာကို ဘာသာပြန် မရနိုင်ခဲ့ပါ။</translation>
-<translation id="6040143037577758943">ပိတ်ရန်</translation>
-<translation id="6831043979455480757">ဘာသာပြန်ရန်</translation>
-<translation id="7243308994586599757">ရွေးစရာများမှာ မျက်နှာပြင်၏ အောက်ခြေပိုင်းနားမှာ ရှိကြသည်</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> ဘာသာဖြင့် စာမျက်နှာများအားလုံးကို အမြဲဘာသာပြန်ရန်</translation>
<translation id="8298278839890148234">ဝဘ်ဘရောင်ဇာ လုပ်ဆောင်ချက်</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ne.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ne.xtb
index 11e137141d1..06ec47e44f4 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ne.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ne.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ne">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> मा भएका पृष्ठहरूलाई कहिल्यै अनुवाद नगर्नुहोस्‌</translation>
-<translation id="124116460088058876">थप भाषाहरू</translation>
-<translation id="1285320974508926690">यो साइट कहिले पनि अनुवाद नगर्नुहोस्</translation>
-<translation id="290376772003165898"><ph name="LANGUAGE" /> भाषामा पृष्ठ छैन?</translation>
-<translation id="5684874026226664614">ओहो। यो पृष्ठ अनुवादन गर्न सकिएन।</translation>
-<translation id="6040143037577758943">बन्द गर्नुहोस्</translation>
-<translation id="6831043979455480757">अनुवाद गर्नुहोस्</translation>
-<translation id="7243308994586599757">विकल्पहरू स्क्रिनको तल नजिकै उपलब्ध छ</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> मा रहेका पृष्ठहरूलाई सधैँ अनुवाद गर्नुहोस्‌</translation>
<translation id="8298278839890148234">ब्राउजर प्रयोग गरी गरिएको क्रियाकलाप</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_nl.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_nl.xtb
index cd20f14e5ca..759b04e50cc 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_nl.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_nl.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="nl">
-<translation id="1068672505746868501">Pagina's in het <ph name="SOURCE_LANGUAGE" /> nooit vertalen</translation>
-<translation id="124116460088058876">Meer talen</translation>
-<translation id="1285320974508926690">Deze site nooit vertalen</translation>
-<translation id="290376772003165898">Is deze pagina niet in het <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Deze pagina kan niet worden vertaald.</translation>
-<translation id="6040143037577758943">Sluiten</translation>
-<translation id="6831043979455480757">Vertalen</translation>
-<translation id="7243308994586599757">Opties beschikbaar onder aan het scherm</translation>
-<translation id="773466115871691567">Pagina's in het <ph name="SOURCE_LANGUAGE" /> altijd vertalen</translation>
<translation id="8298278839890148234">Webbrowseractivititeit</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_no.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_no.xtb
index 0a02095d40b..409a800ee70 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_no.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_no.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="no">
-<translation id="1068672505746868501">Oversett aldri sider på <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Flere språk</translation>
-<translation id="1285320974508926690">Oversett aldri dette nettstedet</translation>
-<translation id="290376772003165898">Er ikke siden på <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Beklager. Denne siden kunne ikke oversettes.</translation>
-<translation id="6040143037577758943">Lukk</translation>
-<translation id="6831043979455480757">Oversett</translation>
-<translation id="7243308994586599757">Du finner alternativer ved bunnen av skjermen</translation>
-<translation id="773466115871691567">Oversett alltid sider på <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Nettleseraktivitet</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_or.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_or.xtb
index 8d046c770c1..f88f14b33c3 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_or.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_or.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="or">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" />ରେ ପୃଷ୍ଠାଗୁଡ଼ିକୁ ଅନୁବାଦ କରନ୍ତୁ ନାହିଁ</translation>
-<translation id="124116460088058876">ଅନେକ ଭାଷା</translation>
-<translation id="1285320974508926690">ଏହି ସାଇଟ୍‍କୁ କଦାପି ଅନୁବାଦ କରନ୍ତୁ ନାହିଁ</translation>
-<translation id="290376772003165898">ପୃଷ୍ଠାଟି <ph name="LANGUAGE" />ରେ ନାହିଁ?</translation>
-<translation id="5684874026226664614">ଓହୋଃ! ଏହି ପୃଷ୍ଠା ଅନୁବାଦ କରାଯାଇପାରିଲା ନାହିଁ।</translation>
-<translation id="6040143037577758943">ବନ୍ଦ</translation>
-<translation id="6831043979455480757">ଅନୁବାଦ କରନ୍ତୁ</translation>
-<translation id="7243308994586599757">ସ୍କ୍ରିନ୍‍ର ନିମ୍ନରେ ବିକଳ୍ପଗୁଡ଼ିକ ଉପଲବ୍ଧ ଅଛି</translation>
-<translation id="773466115871691567">ସର୍ବଦା <ph name="SOURCE_LANGUAGE" />ରେ ପୃଷ୍ଠାଗୁଡ଼ିକୁ ଅନୁବାଦ କରନ୍ତୁ</translation>
<translation id="8298278839890148234">ୱେବ୍ ବ୍ରାଉଜର୍ କାର୍ଯ୍ୟକଳାପ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_pa.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_pa.xtb
index 6394a67f909..0d4c8c78fba 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_pa.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_pa.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pa">
-<translation id="1068672505746868501">ਕਦੇ ਵੀ ਪੰਨਿਆਂ ਦਾ ਅਨੁਵਾਦ <ph name="SOURCE_LANGUAGE" /> ਵਿੱਚ ਨਾ ਕਰੋ</translation>
-<translation id="124116460088058876">ਹੋਰ ਭਾਸ਼ਾਵਾਂ</translation>
-<translation id="1285320974508926690">ਕਦੇ ਵੀ ਇਸ ਸਾਈਟ ਦਾ ਅਨੁਵਾਦ ਨਾ ਕਰੋ</translation>
-<translation id="290376772003165898">ਕੀ ਪੰਨਾ <ph name="LANGUAGE" /> ਵਿੱਚ ਨਹੀਂ ਹੈ?</translation>
-<translation id="5684874026226664614">ਓਹੋ। ਇਸ ਪੰਨੇ ਦਾ ਅਨੁਵਾਦ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।</translation>
-<translation id="6040143037577758943">ਬੰਦ ਕਰੋ</translation>
-<translation id="6831043979455480757">ਅਨੁਵਾਦ ਕਰੋ</translation>
-<translation id="7243308994586599757">ਵਿਕਲਪ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਪਾਸੇ ਦੇ ਕੋਲ ਉਪਲਬਧ ਹਨ</translation>
-<translation id="773466115871691567">ਪੰਨਿਆਂ ਦਾ ਅਨੁਵਾਦ ਹਮੇਸ਼ਾਂ <ph name="SOURCE_LANGUAGE" /> ਭਾਸ਼ਾ ਵਿੱਚ ਕਰੋ</translation>
<translation id="8298278839890148234">ਵੈੱਬ ਬ੍ਰਾਊਜ਼ਰ ਸਰਗਰਮੀ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_pl.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_pl.xtb
index 2185aeb5d3d..52a394f3e02 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_pl.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_pl.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pl">
-<translation id="1068672505746868501">Nigdy nie tłumacz stron, których językiem jest <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Więcej języków</translation>
-<translation id="1285320974508926690">Nigdy nie tłumacz tej witryny</translation>
-<translation id="290376772003165898">Język tej strony to nie <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Nie można przetłumaczyć tej strony.</translation>
-<translation id="6040143037577758943">Zamknij</translation>
-<translation id="6831043979455480757">Tłumacz</translation>
-<translation id="7243308994586599757">Opcje dostępne u dołu ekranu</translation>
-<translation id="773466115871691567">Zawsze tłumacz strony, których językiem jest <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Aktywność w przeglądarce</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_pt-BR.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_pt-BR.xtb
index 45880dbbefa..dd6972f79e3 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_pt-BR.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_pt-BR.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pt-BR">
-<translation id="1068672505746868501">Nunca traduzir páginas em <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Mais idiomas</translation>
-<translation id="1285320974508926690">Nunca traduzir este site</translation>
-<translation id="290376772003165898">A página não está em <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Não foi possível traduzir esta página.</translation>
-<translation id="6040143037577758943">Fechar</translation>
-<translation id="6831043979455480757">Traduzir</translation>
-<translation id="7243308994586599757">Opções disponíveis perto da parte inferior da tela</translation>
-<translation id="773466115871691567">Sempre traduzir páginas em <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Atividade do navegador da Web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_pt-PT.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_pt-PT.xtb
index 0b06168100d..76966566f3d 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_pt-PT.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_pt-PT.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pt-PT">
-<translation id="1068672505746868501">Nunca traduzir páginas em <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Mais idiomas</translation>
-<translation id="1285320974508926690">Nunca traduzir este site</translation>
-<translation id="290376772003165898">A página não está em <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Ups! Não foi possível traduzir esta página.</translation>
-<translation id="6040143037577758943">Fechar</translation>
-<translation id="6831043979455480757">Traduzir</translation>
-<translation id="7243308994586599757">Opções disponíveis junto à parte inferior do ecrã</translation>
-<translation id="773466115871691567">Traduza sempre páginas em <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Atividade do navegador de Internet</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ro.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ro.xtb
index 87a6bce7c07..12f45d28945 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ro.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ro.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ro">
-<translation id="1068672505746868501">Nu traduce niciodată paginile în <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Mai multe limbi</translation>
-<translation id="1285320974508926690">Nu traduce niciodată acest site</translation>
-<translation id="290376772003165898">Pagina nu este în <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Hopa. Această pagină nu a putut fi tradusă.</translation>
-<translation id="6040143037577758943">Închide</translation>
-<translation id="6831043979455480757">Tradu</translation>
-<translation id="7243308994586599757">Opțiuni disponibile în partea de jos a ecranului</translation>
-<translation id="773466115871691567">Tradu întotdeauna paginile în <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Activitatea în browserul web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ru.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ru.xtb
index 733f199d730..401647df65a 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ru.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ru.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ru">
-<translation id="1068672505746868501">Не переводить страницы на этом языке: <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Другие языки</translation>
-<translation id="1285320974508926690">Никогда не переводить этот сайт</translation>
-<translation id="290376772003165898">Язык страницы не <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Не удалось перевести страницу</translation>
-<translation id="6040143037577758943">Закрыть</translation>
-<translation id="6831043979455480757">Перевести</translation>
-<translation id="7243308994586599757">Доступные параметры указаны в нижней части экрана</translation>
-<translation id="773466115871691567">Переводить страницы на этом языке: <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Действия в веб-браузере</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_si.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_si.xtb
index 90b6f032c71..1e95ef55536 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_si.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_si.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="si">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> හි පිටු කිසිදාක පරිවර්තනය කරන්න එපා</translation>
-<translation id="124116460088058876">තවත් භාෂා</translation>
-<translation id="1285320974508926690">මෙම අඩවිය කිසිවිට පරිවර්තනය නොකරන්න</translation>
-<translation id="290376772003165898">පිටුව <ph name="LANGUAGE" /> බසින් නොවේ ද?</translation>
-<translation id="5684874026226664614">අපොයි. මෙම පිටුව පැටවිය නොහැකි විය.</translation>
-<translation id="6040143037577758943">වසන්න</translation>
-<translation id="6831043979455480757">පරිවර්තනය කරන්න</translation>
-<translation id="7243308994586599757">තිරයේ පහළට ආසන්නව විකල්ප ලබා ගත හැකිය</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> හි පිටු සැමවිටම පරිවර්තනය කරන්න</translation>
<translation id="8298278839890148234">වෙබ් බ්‍රවුසර ක්‍රියාකාරකම</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_sk.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_sk.xtb
index fe4bb0c1612..53b2d4ec263 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_sk.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_sk.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sk">
-<translation id="1068672505746868501">Nikdy neprekladať stránky v jazyku <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Ďalšie jazyky</translation>
-<translation id="1285320974508926690">Nikdy neprekladať tieto webové stránky</translation>
-<translation id="290376772003165898">Stránka nie je v jazyku <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Hops. Túto stránku nebolo možné preložiť.</translation>
-<translation id="6040143037577758943">Zavrieť</translation>
-<translation id="6831043979455480757">Preložiť</translation>
-<translation id="7243308994586599757">Možnosti sú k dispozícii v dolnej časti obrazovky</translation>
-<translation id="773466115871691567">Vždy prekladať stránky v jazyku <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Aktivita webového prehliadača</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_sl.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_sl.xtb
index bc91c54ae43..152968ea560 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_sl.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_sl.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sl">
-<translation id="1068672505746868501">Nikoli ne prevedi strani v jeziku <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Več jezikov</translation>
-<translation id="1285320974508926690">Nikoli ne prevedi tega spletnega mesta</translation>
-<translation id="290376772003165898">Stran ni v jeziku <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Ojoj, te strani bi bilo mogoče prevesti.</translation>
-<translation id="6040143037577758943">Zapri</translation>
-<translation id="6831043979455480757">Prevedi</translation>
-<translation id="7243308994586599757">Možnosti so na voljo pri dnu zaslona</translation>
-<translation id="773466115871691567">Vedno prevedi strani v jeziku <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Dejavnost brskalnika</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_sq.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_sq.xtb
index c88ab6c0cfc..2e0a6950797 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_sq.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_sq.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sq">
-<translation id="1068672505746868501">Mos përkthe asnjëherë faqet që janë në <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Gjuhë të tjera</translation>
-<translation id="1285320974508926690">Asnjëherë mos e përkthe këtë sajt</translation>
-<translation id="290376772003165898">Faqja nuk është në <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Mos! Kjo faqe nuk mund të përkthehej.</translation>
-<translation id="6040143037577758943">Mbyll</translation>
-<translation id="6831043979455480757">Përkthe</translation>
-<translation id="7243308994586599757">Opsionet janë të disponueshme pranë fundit të ekranit</translation>
-<translation id="773466115871691567">Përkthe gjithmonë faqet që janë në <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Aktiviteti i shfletuesit të uebit</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_sr-Latn.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_sr-Latn.xtb
index d66789dacf8..24f260082a7 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_sr-Latn.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_sr-Latn.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sr-Latn">
-<translation id="1068672505746868501">Nikad ne prevodi stranice na jeziku <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Još jezika</translation>
-<translation id="1285320974508926690">Nikad ne prevodi ovaj sajt</translation>
-<translation id="290376772003165898">Ova stranica nije na jeziku <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Ups, prevođenje ove stranice nije uspelo.</translation>
-<translation id="6040143037577758943">Zatvori</translation>
-<translation id="6831043979455480757">Prevedi</translation>
-<translation id="7243308994586599757">Opcije su dostupne u dnu ekrana</translation>
-<translation id="773466115871691567">Uvek predvodi stranice na jeziku <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Aktivnosti u veb-pregledaču</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_sr.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_sr.xtb
index d5eb9aa0fef..9008032cbef 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_sr.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_sr.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sr">
-<translation id="1068672505746868501">Никад не преводи странице на језику <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Још језика</translation>
-<translation id="1285320974508926690">Никад не преводи овај сајт</translation>
-<translation id="290376772003165898">Ова страница није на језику <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Упс, превођење ове странице није успело.</translation>
-<translation id="6040143037577758943">Затвори</translation>
-<translation id="6831043979455480757">Преведи</translation>
-<translation id="7243308994586599757">Опције су доступне у дну екрана</translation>
-<translation id="773466115871691567">Увек предводи странице на језику <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Активности у веб-прегледачу</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_sv.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_sv.xtb
index 532dc6eb359..610cb47e53f 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_sv.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_sv.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sv">
-<translation id="1068672505746868501">Översätt aldrig sidor på <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Fler språk</translation>
-<translation id="1285320974508926690">Översätt aldrig den här webbplatsen</translation>
-<translation id="290376772003165898">Är sidan inte på <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Det gick inte att översätta sidan.</translation>
-<translation id="6040143037577758943">Stäng</translation>
-<translation id="6831043979455480757">Översätt</translation>
-<translation id="7243308994586599757">Alternativ visas nära skärmens nedre kant</translation>
-<translation id="773466115871691567">Översätt alltid sidor på <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Webbläsaraktivitet</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_sw.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_sw.xtb
index 2854041492f..cf0a4b711da 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_sw.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_sw.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sw">
-<translation id="1068672505746868501">Usiwahi kutafsiri kurasa katika lugha ya <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Lugha zaidi</translation>
-<translation id="1285320974508926690">Kamwe usitafsiri tovuti hii</translation>
-<translation id="290376772003165898">Je, ukurasa huu haupo katika <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Lo! Ukurasa huu haukuweza kutafsiriwa.</translation>
-<translation id="6040143037577758943">Funga</translation>
-<translation id="6831043979455480757">Tafsiri</translation>
-<translation id="7243308994586599757">Chaguo zinapatikana karibu na sehemu ya chini ya skrini</translation>
-<translation id="773466115871691567">Zitafsiri kurasa katika <ph name="SOURCE_LANGUAGE" /> wakati wote</translation>
<translation id="8298278839890148234">Shughuli za kivinjari</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ta.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ta.xtb
index c7f7130e4c5..8a47545a26a 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ta.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ta.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ta">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> மொழியில் உள்ள பக்கங்களை ஒருபோதும் மொழிபெயர்க்காதே</translation>
-<translation id="124116460088058876">மேலும் மொழிகள்</translation>
-<translation id="1285320974508926690">இந்த தளத்தை எப்போதும் மொழிபெயர்க்க வேண்டாம்</translation>
-<translation id="290376772003165898"><ph name="LANGUAGE" /> மொழியில் பக்கம் இல்லையா?</translation>
-<translation id="5684874026226664614">அச்சச்சோ. இந்தப் பக்கத்தை மொழிபெயர்க்க முடியாது.</translation>
-<translation id="6040143037577758943">மூடு</translation>
-<translation id="6831043979455480757">மொழிபெயர்</translation>
-<translation id="7243308994586599757">திரையின் கீழ்ப்பகுதிக்கு அருகில் கிடைக்கும் விருப்பங்கள்</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> மொழியில் உள்ள பக்கங்களை எப்போதும் மொழிபெயர்</translation>
<translation id="8298278839890148234">இணைய உலாவியின் செயல்பாடு</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_te.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_te.xtb
index 53279940602..3894c532d87 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_te.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_te.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="te">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" />లో ఉన్న పేజీలను ఎప్పుడూ అనువదించవద్దు</translation>
-<translation id="124116460088058876">మరిన్ని భాషలు</translation>
-<translation id="1285320974508926690">ఈ సైట్‌ను ఎప్పటికీ అనువదించవద్దు</translation>
-<translation id="290376772003165898">పేజీ <ph name="LANGUAGE" />లో లేదా?</translation>
-<translation id="5684874026226664614">అయ్యో. ఈ పేజీని అనువదించడం సాధ్యపడలేదు.</translation>
-<translation id="6040143037577758943">మూసివేయి</translation>
-<translation id="6831043979455480757">అనువదించు</translation>
-<translation id="7243308994586599757">స్క్రీన్ దిగువభాగం సమీపంలో ఎంపికలు అందుబాటులో ఉంటాయి</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" />లో ఉన్న పేజీలను ఎల్లప్పుడూ అనువదించు</translation>
<translation id="8298278839890148234">బ్రౌజింగ్ యాక్టివిటీ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_th.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_th.xtb
index 024e4b547a9..1c8e14c9ca0 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_th.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_th.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="th">
-<translation id="1068672505746868501">ไม่ต้องแปลหน้าเว็บภาษา<ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">ภาษาเพิ่มเติม</translation>
-<translation id="1285320974508926690">ไม่ต้องแปลเว็บไซต์นี้</translation>
-<translation id="290376772003165898">หน้านี้ไม่ใช่ภาษา<ph name="LANGUAGE" />ใช่ไหม</translation>
-<translation id="5684874026226664614">อ๊ะ หน้านี้ไม่สามารถแปลได้</translation>
-<translation id="6040143037577758943">ปิด</translation>
-<translation id="6831043979455480757">แปลภาษา</translation>
-<translation id="7243308994586599757">มีตัวเลือกอยู่ทางด้านล่างของหน้าจอ</translation>
-<translation id="773466115871691567">แปลหน้าเว็บภาษา<ph name="SOURCE_LANGUAGE" />ทุกครั้ง</translation>
<translation id="8298278839890148234">กิจกรรมของเว็บเบราว์เซอร์</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_tr.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_tr.xtb
index 2f9a035ea1b..11d4ab4aeef 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_tr.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_tr.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="tr">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> dilindeki sayfaları asla çevirme</translation>
-<translation id="124116460088058876">Diğer diller</translation>
-<translation id="1285320974508926690">Bu siteyi hiçbir zaman çevirme</translation>
-<translation id="290376772003165898">Sayfa <ph name="LANGUAGE" /> dilinde değil mi?</translation>
-<translation id="5684874026226664614">Hata! Bu sayfa çevrilemedi.</translation>
-<translation id="6040143037577758943">Kapat</translation>
-<translation id="6831043979455480757">Çevir</translation>
-<translation id="7243308994586599757">Sayfanın altına yakın bir yerde kullanılabilen seçenekler</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> dilindeki sayfaları her zaman çevir</translation>
<translation id="8298278839890148234">Web tarayıcısı etkinliği</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_uk.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_uk.xtb
index 4a29de8edb5..f8630458317 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_uk.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_uk.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="uk">
-<translation id="1068672505746868501">Ніколи не перекладати сторінки такою мовою: <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Інші мови</translation>
-<translation id="1285320974508926690">Ніколи не перекладати цей сайт</translation>
-<translation id="290376772003165898">Ця сторінка відображається не такою мовою: <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">На жаль, цю сторінку неможливо перекласти.</translation>
-<translation id="6040143037577758943">Закрити</translation>
-<translation id="6831043979455480757">Перекласти</translation>
-<translation id="7243308994586599757">Опції можна знайти внизу екрана</translation>
-<translation id="773466115871691567">Завжди перекладати сторінки такою мовою: <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Дії у веб-переглядачі</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_ur.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_ur.xtb
index 4113ad7cdaa..57e46884972 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_ur.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_ur.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ur">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> کے صفحات کا کبھی ترجمہ نہ کریں</translation>
-<translation id="124116460088058876">مزید زبانیں</translation>
-<translation id="1285320974508926690">اس سائٹ کا ترجمہ کبھی نہ کریں</translation>
-<translation id="290376772003165898">صفحہ <ph name="LANGUAGE" /> میں نہیں ہے؟</translation>
-<translation id="5684874026226664614">افوہ۔ اس صفحہ کا ترجمہ نہیں کیا جا سکا۔</translation>
-<translation id="6040143037577758943">بند کریں</translation>
-<translation id="6831043979455480757">ترجمہ کریں</translation>
-<translation id="7243308994586599757">اسکرین کے نچلے حصہ کے قریب اختیارات دستیاب ہیں</translation>
-<translation id="773466115871691567">ہمیشہ <ph name="SOURCE_LANGUAGE" /> کے صفحات کا ترجمہ کریں</translation>
<translation id="8298278839890148234">ویب براؤزر کی سرگرمی</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_uz.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_uz.xtb
index f0af58d90cd..92655c71edf 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_uz.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_uz.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="uz">
-<translation id="1068672505746868501"><ph name="SOURCE_LANGUAGE" /> tilidagi sahifalar hech qachon tarjima qilinmasin</translation>
-<translation id="124116460088058876">Boshqa tillar</translation>
-<translation id="1285320974508926690">Bu sayt hech qachon tarjima qilinmasin</translation>
-<translation id="290376772003165898">Sahifa <ph name="LANGUAGE" /> tilida emasmi?</translation>
-<translation id="5684874026226664614">Bu sahifani tarjima qilib bo‘lmadi.</translation>
-<translation id="6040143037577758943">Yopish</translation>
-<translation id="6831043979455480757">Tarjima</translation>
-<translation id="7243308994586599757">Parametrlar ekranning quyi qismiga yaqinroq joyda</translation>
-<translation id="773466115871691567"><ph name="SOURCE_LANGUAGE" /> tilidagi sahifalar doim tarjima qilinsin</translation>
<translation id="8298278839890148234">Veb-brauzerdagi faoliyat</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_vi.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_vi.xtb
index 2744201fd71..2f57bd60947 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_vi.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_vi.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="vi">
-<translation id="1068672505746868501">Không bao giờ dịch các trang viết bằng <ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Ngôn ngữ khác</translation>
-<translation id="1285320974508926690">Không bao giờ dịch trang web này</translation>
-<translation id="290376772003165898">Trang này không được viết bằng <ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Rất tiếc. Không thể dịch trang này.</translation>
-<translation id="6040143037577758943">Đóng</translation>
-<translation id="6831043979455480757">Dịch</translation>
-<translation id="7243308994586599757">Có các tùy chọn ở gần cuối màn hình</translation>
-<translation id="773466115871691567">Luôn dịch các trang viết bằng <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Hoạt động duyệt web</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_zh-CN.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_zh-CN.xtb
index 0c3183bb774..84075ec9807 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_zh-CN.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_zh-CN.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-CN">
-<translation id="1068672505746868501">一律不翻译<ph name="SOURCE_LANGUAGE" />网页</translation>
-<translation id="124116460088058876">更多语言</translation>
-<translation id="1285320974508926690">一律不翻译此网站</translation>
-<translation id="290376772003165898">网页的源语言不是<ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">糟糕,此网页内容无法翻译。</translation>
-<translation id="6040143037577758943">关闭</translation>
-<translation id="6831043979455480757">翻译</translation>
-<translation id="7243308994586599757">选项在靠近屏幕底部的位置</translation>
-<translation id="773466115871691567">一律翻译<ph name="SOURCE_LANGUAGE" />网页</translation>
<translation id="8298278839890148234">网络浏览器活动</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_zh-HK.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_zh-HK.xtb
index 3b6aab868dd..abd42fba040 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_zh-HK.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_zh-HK.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-HK">
-<translation id="1068672505746868501">永不翻譯來源語言為<ph name="SOURCE_LANGUAGE" />的網頁</translation>
-<translation id="124116460088058876">更多語言</translation>
-<translation id="1285320974508926690">永不翻譯此網站</translation>
-<translation id="290376772003165898">網頁的來源語言不是<ph name="LANGUAGE" />嗎?</translation>
-<translation id="5684874026226664614">糟糕!系統無法翻譯這個網頁的內容。</translation>
-<translation id="6040143037577758943">關閉</translation>
-<translation id="6831043979455480757">翻譯</translation>
-<translation id="7243308994586599757">您可在畫面底部附近找到選項</translation>
-<translation id="773466115871691567">一律翻譯來源語言為<ph name="SOURCE_LANGUAGE" />的網頁</translation>
<translation id="8298278839890148234">網絡瀏覽器活動</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_zh-TW.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_zh-TW.xtb
index d338d98229a..ecea64ea7f4 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_zh-TW.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_zh-TW.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-TW">
-<translation id="1068672505746868501">一律不翻譯<ph name="SOURCE_LANGUAGE" />網頁</translation>
-<translation id="124116460088058876">更多語言</translation>
-<translation id="1285320974508926690">一律不翻譯此網站</translation>
-<translation id="290376772003165898">不是<ph name="LANGUAGE" />網頁嗎?</translation>
-<translation id="5684874026226664614">糟糕!系統無法翻譯這個網頁的內容。</translation>
-<translation id="6040143037577758943">關閉</translation>
-<translation id="6831043979455480757">翻譯</translation>
-<translation id="7243308994586599757">選項在接近畫面底部的位置</translation>
-<translation id="773466115871691567">一律翻譯<ph name="SOURCE_LANGUAGE" />網頁</translation>
<translation id="8298278839890148234">網路瀏覽器活動</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/translations/weblayer_strings_zu.xtb b/chromium/weblayer/browser/java/translations/weblayer_strings_zu.xtb
index 9e01afbe908..1da5d91a768 100644
--- a/chromium/weblayer/browser/java/translations/weblayer_strings_zu.xtb
+++ b/chromium/weblayer/browser/java/translations/weblayer_strings_zu.xtb
@@ -1,14 +1,5 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zu">
-<translation id="1068672505746868501">Ungahumushi amakhasi ngesi-<ph name="SOURCE_LANGUAGE" /></translation>
-<translation id="124116460088058876">Izilimi eziningi</translation>
-<translation id="1285320974508926690">Ungalokothi uhumushe leli sayithi</translation>
-<translation id="290376772003165898">Ikhasi alikho ngesi-<ph name="LANGUAGE" />?</translation>
-<translation id="5684874026226664614">Eshu. Leli khasi alikwazi ukuhunyushwa.</translation>
-<translation id="6040143037577758943">Vala</translation>
-<translation id="6831043979455480757">Humusha</translation>
-<translation id="7243308994586599757">Izinketho ziyatholakala eduze kwangaphansi kwesikrini</translation>
-<translation id="773466115871691567">Njalo humusha amakhasi ngesi-<ph name="SOURCE_LANGUAGE" /></translation>
<translation id="8298278839890148234">Umsebenzi wesiphequluli sewebhu</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/weblayer/browser/java/weblayer_strings.grd b/chromium/weblayer/browser/java/weblayer_strings.grd
index 79a4dcddd27..cd1e72cc645 100644
--- a/chromium/weblayer/browser/java/weblayer_strings.grd
+++ b/chromium/weblayer/browser/java/weblayer_strings.grd
@@ -172,34 +172,6 @@
<message name="IDS_WEBLAYER_NOTIFICATION_CHANNEL_GROUP_NAME" desc="The user-facing label for the notification channel group used for notifications arising from web browsing activity.">
Web browser activity
</message>
- <message name="IDS_WEBLAYER_BOTTOM_BAR_SCREEN_POSITION" desc="Accessibility label to inform users about the InfoBar location">
- Options available near bottom of the screen
- </message>
- <message name="IDS_WEBLAYER_INFOBAR_CLOSE" desc="Accessibility label for the dismiss infobar Button">
- Close
- </message>
- <!-- TranslateInfoBar -->
- <message name="IDS_TRANSLATE_INFOBAR_ERROR">
- Oops. This page could not be translated.
- </message>
- <message name="IDS_TRANSLATE_BUTTON" desc="Possible texts to display on the translate infobar buttons. [CHAR-LIMIT=24]">
- Translate
- </message>
- <message name="IDS_TRANSLATE_NEVER_TRANSLATE_SITE" desc="Text to display on the never translate site (like www.google.com) button. [CHAR-LIMIT=64]">
- Never translate this site
- </message>
- <message name="IDS_TRANSLATE_OPTION_ALWAYS_TRANSLATE" desc="Option in the Chrome menu. User can click the 'Always Translate' option to indicate that they want Chrome to translate pages in this language automatically. Imperative.">
- Always translate pages in <ph name="SOURCE_LANGUAGE">%1$s<ex>French</ex></ph>
- </message>
- <message name="IDS_TRANSLATE_OPTION_NEVER_TRANSLATE" desc="Option in the Chrome menu. User can click the 'Never Translate' option to indicate that they never want Chrome to translate pages in this language. The variable SOURCE_LANGUAGE could be any of 50+ languages supported by Google Translate, like French, Spanish, German, Italian, Japanese, Korean, etc. Imperative.">
- Never translate pages in <ph name="SOURCE_LANGUAGE">%1$s<ex>French</ex></ph>
- </message>
- <message name="IDS_TRANSLATE_OPTION_MORE_LANGUAGE" desc="Option in the Chrome menu. Lets the user open a dialog to choose other target languages for translation, from a list of available languages. [CHAR-LIMIT=64]">
- More languages
- </message>
- <message name="IDS_TRANSLATE_OPTION_NOT_SOURCE_LANGUAGE" desc="Option in the Chrome menu. Sometimes a web page's source language is not correctly identified by Google Translate, and this menu option lets the user open a submenu to select another language as the source language to translate. Phrased as a question as if to query the user, 'Is this page not in [source language identified]? If so, click here.' [CHAR-LIMIT=64]">
- Page is not in <ph name="LANGUAGE">%1$s<ex>French</ex></ph>?
- </message>
</messages>
</release>
</grit>
diff --git a/chromium/weblayer/browser/navigation_browsertest.cc b/chromium/weblayer/browser/navigation_browsertest.cc
index c573269cc60..283e284874f 100644
--- a/chromium/weblayer/browser/navigation_browsertest.cc
+++ b/chromium/weblayer/browser/navigation_browsertest.cc
@@ -8,18 +8,22 @@
#include "base/files/file_path.h"
#include "base/test/bind_test_util.h"
#include "components/variations/net/variations_http_headers.h"
-#include "components/variations/variations_http_header_provider.h"
+#include "components/variations/variations_ids_provider.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/test/browser_test_utils.h"
#include "content/public/test/url_loader_interceptor.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/controllable_http_response.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_response.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/public/browser.h"
#include "weblayer/public/navigation.h"
#include "weblayer/public/navigation_controller.h"
#include "weblayer/public/navigation_observer.h"
-#include "weblayer/public/tab.h"
#include "weblayer/shell/browser/shell.h"
#include "weblayer/test/interstitial_utils.h"
+#include "weblayer/test/test_navigation_observer.h"
#include "weblayer/test/weblayer_browser_test_utils.h"
namespace weblayer {
@@ -68,8 +72,11 @@ class NavigationObserverImpl : public NavigationObserver {
completed_callback_.Run(navigation);
}
void NavigationFailed(Navigation* navigation) override {
- if (failed_callback_)
- failed_callback_.Run(navigation);
+ // As |this| may be deleted when running the callback, the callback must be
+ // copied before running. To do otherwise results in use-after-free.
+ auto callback = failed_callback_;
+ if (callback)
+ callback.Run(navigation);
}
private:
@@ -80,56 +87,6 @@ class NavigationObserverImpl : public NavigationObserver {
Callback failed_callback_;
};
-class OneShotNavigationObserver : public NavigationObserver {
- public:
- explicit OneShotNavigationObserver(Shell* shell) : tab_(shell->tab()) {
- tab_->GetNavigationController()->AddObserver(this);
- }
-
- ~OneShotNavigationObserver() override {
- tab_->GetNavigationController()->RemoveObserver(this);
- }
-
- void WaitForNavigation() { run_loop_.Run(); }
-
- bool completed() { return completed_; }
- bool is_error_page() { return is_error_page_; }
- bool is_download() { return is_download_; }
- bool was_stop_called() { return was_stop_called_; }
- Navigation::LoadError load_error() { return load_error_; }
- int http_status_code() { return http_status_code_; }
- NavigationState navigation_state() { return navigation_state_; }
-
- private:
- // NavigationObserver implementation:
- void NavigationCompleted(Navigation* navigation) override {
- completed_ = true;
- Finish(navigation);
- }
-
- void NavigationFailed(Navigation* navigation) override { Finish(navigation); }
-
- void Finish(Navigation* navigation) {
- is_error_page_ = navigation->IsErrorPage();
- is_download_ = navigation->IsDownload();
- was_stop_called_ = navigation->WasStopCalled();
- load_error_ = navigation->GetLoadError();
- http_status_code_ = navigation->GetHttpStatusCode();
- navigation_state_ = navigation->GetState();
- run_loop_.Quit();
- }
-
- base::RunLoop run_loop_;
- Tab* tab_;
- bool completed_ = false;
- bool is_error_page_ = false;
- bool is_download_ = false;
- bool was_stop_called_ = false;
- Navigation::LoadError load_error_ = Navigation::kNoError;
- int http_status_code_ = 0;
- NavigationState navigation_state_ = NavigationState::kWaitingResponse;
-};
-
} // namespace
class NavigationBrowserTest : public WebLayerBrowserTest {
@@ -150,6 +107,7 @@ IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, NoError) {
EXPECT_TRUE(observer.completed());
EXPECT_FALSE(observer.is_error_page());
EXPECT_FALSE(observer.is_download());
+ EXPECT_FALSE(observer.is_reload());
EXPECT_FALSE(observer.was_stop_called());
EXPECT_EQ(observer.load_error(), Navigation::kNoError);
EXPECT_EQ(observer.http_status_code(), 200);
@@ -255,6 +213,25 @@ IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, StopInOnStart) {
run_loop.Run();
}
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, DestroyTabInNavigation) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ Tab* new_tab = shell()->browser()->CreateTab();
+ base::RunLoop run_loop;
+ std::unique_ptr<NavigationObserverImpl> observer =
+ std::make_unique<NavigationObserverImpl>(
+ new_tab->GetNavigationController());
+ observer->SetFailedCallback(
+ base::BindLambdaForTesting([&](Navigation* navigation) {
+ observer.reset();
+ shell()->browser()->DestroyTab(new_tab);
+ run_loop.Quit();
+ }));
+ new_tab->GetNavigationController()->Navigate(
+ embedded_test_server()->GetURL("/simple_pageX.html"));
+
+ run_loop.Run();
+}
+
IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, StopInOnRedirect) {
ASSERT_TRUE(embedded_test_server()->Start());
base::RunLoop run_loop;
@@ -438,6 +415,22 @@ IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, PageSeesUserAgentString) {
run_loop.Run();
}
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, Reload) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ OneShotNavigationObserver observer(shell());
+ GetNavigationController()->Navigate(
+ embedded_test_server()->GetURL("/simple_page.html"));
+ observer.WaitForNavigation();
+
+ OneShotNavigationObserver observer2(shell());
+ shell()->tab()->ExecuteScript(base::ASCIIToUTF16("location.reload();"), false,
+ base::DoNothing());
+ observer2.WaitForNavigation();
+ EXPECT_TRUE(observer2.completed());
+ EXPECT_TRUE(observer2.is_reload());
+}
+
IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, SetUserAgentString) {
net::test_server::ControllableHttpResponse response_1(embedded_test_server(),
"", true);
@@ -598,6 +591,63 @@ IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
EXPECT_EQ(custom_ua, new_ua);
}
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, AutoPlayDefault) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ GURL url(embedded_test_server()->GetURL("/autoplay.html"));
+ auto* tab = static_cast<TabImpl*>(shell()->tab());
+ NavigateAndWaitForCompletion(url, tab);
+
+ auto* web_contents = tab->web_contents();
+ bool playing = false;
+ // There's no notification to watch that would signal video wasn't autoplayed,
+ // so instead check once through javascript.
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ web_contents,
+ "window.domAutomationController.send(!document.getElementById('vid')."
+ "paused)",
+ &playing));
+ ASSERT_FALSE(playing);
+}
+
+namespace {
+
+class WaitForMediaPlaying : public content::WebContentsObserver {
+ public:
+ explicit WaitForMediaPlaying(content::WebContents* web_contents)
+ : WebContentsObserver(web_contents) {}
+
+ // WebContentsObserver override.
+ void MediaStartedPlaying(const MediaPlayerInfo& info,
+ const content::MediaPlayerId&) final {
+ run_loop_.Quit();
+ CHECK(info.has_audio);
+ CHECK(info.has_video);
+ }
+
+ void Wait() { run_loop_.Run(); }
+
+ private:
+ base::RunLoop run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(WaitForMediaPlaying);
+};
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, AutoPlayEnabled) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ GURL url(embedded_test_server()->GetURL("/autoplay.html"));
+ NavigationController::NavigateParams params;
+ params.enable_auto_play = true;
+ GetNavigationController()->Navigate(url, params);
+
+ auto* tab = static_cast<TabImpl*>(shell()->tab());
+ WaitForMediaPlaying wait_for_media(tab->web_contents());
+ wait_for_media.Wait();
+}
+
class NavigationBrowserTest2 : public NavigationBrowserTest {
public:
void SetUp() override {
@@ -618,7 +668,7 @@ class NavigationBrowserTest2 : public NavigationBrowserTest {
// Forces variations code to set the header.
auto* variations_provider =
- variations::VariationsHttpHeaderProvider::GetInstance();
+ variations::VariationsIdsProvider::GetInstance();
variations_provider->ForceVariationIds({"12", "456", "t789"}, "");
}
diff --git a/chromium/weblayer/browser/navigation_controller_impl.cc b/chromium/weblayer/browser/navigation_controller_impl.cc
index cabbd2cca24..f14bb94f035 100644
--- a/chromium/weblayer/browser/navigation_controller_impl.cc
+++ b/chromium/weblayer/browser/navigation_controller_impl.cc
@@ -14,6 +14,7 @@
#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/page_transition_types.h"
+#include "weblayer/browser/navigation_ui_data_impl.h"
#include "weblayer/browser/tab_impl.h"
#include "weblayer/public/navigation_observer.h"
@@ -31,6 +32,29 @@ using base::android::ScopedJavaLocalRef;
namespace weblayer {
+class NavigationControllerImpl::DelayDeletionHelper {
+ public:
+ explicit DelayDeletionHelper(NavigationControllerImpl* controller)
+ : controller_(controller->weak_ptr_factory_.GetWeakPtr()) {
+ // This should never be called reentrantly.
+ DCHECK(!controller->should_delay_web_contents_deletion_);
+ controller->should_delay_web_contents_deletion_ = true;
+ }
+
+ DelayDeletionHelper(const DelayDeletionHelper&) = delete;
+ DelayDeletionHelper& operator=(const DelayDeletionHelper&) = delete;
+
+ ~DelayDeletionHelper() {
+ if (controller_)
+ controller_->should_delay_web_contents_deletion_ = false;
+ }
+
+ bool WasControllerDeleted() { return controller_.get() == nullptr; }
+
+ private:
+ base::WeakPtr<NavigationControllerImpl> controller_;
+};
+
// NavigationThrottle implementation responsible for delaying certain
// operations and performing them when safe. This is necessary as content
// does allow certain operations to be called at certain times. For example,
@@ -111,6 +135,12 @@ NavigationControllerImpl::CreateNavigationThrottle(
return throttle;
}
+NavigationImpl* NavigationControllerImpl::GetNavigationImplFromHandle(
+ content::NavigationHandle* handle) {
+ auto iter = navigation_map_.find(handle);
+ return iter == navigation_map_.end() ? nullptr : iter->second.get();
+}
+
#if defined(OS_ANDROID)
void NavigationControllerImpl::SetNavigationControllerImpl(
JNIEnv* env,
@@ -118,18 +148,28 @@ void NavigationControllerImpl::SetNavigationControllerImpl(
java_controller_ = java_controller;
}
-void NavigationControllerImpl::Navigate(JNIEnv* env,
- const JavaParamRef<jstring>& url) {
- Navigate(GURL(base::android::ConvertJavaStringToUTF8(env, url)));
-}
-
-void NavigationControllerImpl::NavigateWithParams(
+void NavigationControllerImpl::Navigate(
JNIEnv* env,
const JavaParamRef<jstring>& url,
- jboolean should_replace_current_entry) {
+ jboolean should_replace_current_entry,
+ jboolean disable_intent_processing,
+ jboolean disable_network_error_auto_reload,
+ jboolean enable_auto_play) {
auto params = std::make_unique<content::NavigationController::LoadURLParams>(
GURL(base::android::ConvertJavaStringToUTF8(env, url)));
params->should_replace_current_entry = should_replace_current_entry;
+ // On android, the transition type largely dictates whether intent processing
+ // happens. PAGE_TRANSITION_TYPED does not process intents, where as
+ // PAGE_TRANSITION_LINK will (with the caveat that even links may not trigger
+ // intent processing under some circumstances).
+ params->transition_type = disable_intent_processing
+ ? ui::PAGE_TRANSITION_TYPED
+ : ui::PAGE_TRANSITION_LINK;
+ if (disable_network_error_auto_reload)
+ params->navigation_ui_data = std::make_unique<NavigationUIDataImpl>(true);
+ if (enable_auto_play)
+ params->was_activated = content::mojom::WasActivatedOption::kYes;
+
DoNavigate(std::move(params));
}
@@ -197,6 +237,13 @@ void NavigationControllerImpl::Navigate(
std::make_unique<content::NavigationController::LoadURLParams>(url);
load_params->should_replace_current_entry =
params.should_replace_current_entry;
+ if (params.disable_network_error_auto_reload) {
+ load_params->navigation_ui_data =
+ std::make_unique<NavigationUIDataImpl>(true);
+ }
+ if (params.enable_auto_play)
+ load_params->was_activated = content::mojom::WasActivatedOption::kYes;
+
DoNavigate(std::move(load_params));
}
@@ -335,6 +382,7 @@ void NavigationControllerImpl::DidFinishNavigation(
if (!navigation_handle->IsInMainFrame())
return;
+ DelayDeletionHelper deletion_helper(this);
DCHECK(navigation_map_.find(navigation_handle) != navigation_map_.end());
auto* navigation = navigation_map_[navigation_handle].get();
if (navigation_handle->GetNetErrorCode() == net::OK &&
@@ -346,10 +394,15 @@ void NavigationControllerImpl::DidFinishNavigation(
Java_NavigationControllerImpl_navigationCompleted(
AttachCurrentThread(), java_controller_,
navigation->java_navigation());
+ if (deletion_helper.WasControllerDeleted())
+ return;
}
#endif
- for (auto& observer : observers_)
+ for (auto& observer : observers_) {
observer.NavigationCompleted(navigation);
+ if (deletion_helper.WasControllerDeleted())
+ return;
+ }
} else {
#if defined(OS_ANDROID)
if (java_controller_) {
@@ -358,10 +411,15 @@ void NavigationControllerImpl::DidFinishNavigation(
Java_NavigationControllerImpl_navigationFailed(
AttachCurrentThread(), java_controller_,
navigation->java_navigation());
+ if (deletion_helper.WasControllerDeleted())
+ return;
}
#endif
- for (auto& observer : observers_)
+ for (auto& observer : observers_) {
observer.NavigationFailed(navigation);
+ if (deletion_helper.WasControllerDeleted())
+ return;
+ }
}
// Note InsertVisualStateCallback currently does not take into account
@@ -459,11 +517,6 @@ void NavigationControllerImpl::DoNavigate(
return;
}
- // For WebLayer's production use cases, navigations from the embedder are most
- // appropriately viewed as being from links with user gestures. In particular,
- // this ensures that intents resulting from these navigations get launched as
- // the embedder expects.
- params->transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
params->has_user_gesture = true;
web_contents()->GetController().LoadURLWithParams(*params);
// So that if the user had entered the UI in a bar it stops flashing the
diff --git a/chromium/weblayer/browser/navigation_controller_impl.h b/chromium/weblayer/browser/navigation_controller_impl.h
index ce96e147504..f27153add07 100644
--- a/chromium/weblayer/browser/navigation_controller_impl.h
+++ b/chromium/weblayer/browser/navigation_controller_impl.h
@@ -22,10 +22,12 @@
#endif
namespace content {
+class NavigationHandle;
class NavigationThrottle;
}
namespace weblayer {
+class NavigationImpl;
class TabImpl;
class NavigationControllerImpl : public NavigationController,
@@ -39,15 +41,20 @@ class NavigationControllerImpl : public NavigationController,
std::unique_ptr<content::NavigationThrottle> CreateNavigationThrottle(
content::NavigationHandle* handle);
+ // Returns the NavigationImpl for |handle|, or null if there isn't one.
+ NavigationImpl* GetNavigationImplFromHandle(
+ content::NavigationHandle* handle);
+
#if defined(OS_ANDROID)
void SetNavigationControllerImpl(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& java_controller);
void Navigate(JNIEnv* env,
- const base::android::JavaParamRef<jstring>& url);
- void NavigateWithParams(JNIEnv* env,
- const base::android::JavaParamRef<jstring>& url,
- jboolean should_replace_current_entry);
+ const base::android::JavaParamRef<jstring>& url,
+ jboolean should_replace_current_entry,
+ jboolean disable_intent_processing,
+ jboolean disable_network_error_auto_reload,
+ jboolean enable_auto_play);
void GoBack(JNIEnv* env) { GoBack(); }
void GoForward(JNIEnv* env) { GoForward(); }
bool CanGoBack(JNIEnv* env) { return CanGoBack(); }
@@ -68,7 +75,13 @@ class NavigationControllerImpl : public NavigationController,
bool IsNavigationEntrySkippable(JNIEnv* env, int index);
#endif
+ bool should_delay_web_contents_deletion() {
+ return should_delay_web_contents_deletion_;
+ }
+
private:
+ class DelayDeletionHelper;
+
class NavigationThrottleImpl;
// Called from NavigationControllerImpl::WillRedirectRequest(). See
@@ -129,6 +142,11 @@ class NavigationControllerImpl : public NavigationController,
base::android::ScopedJavaGlobalRef<jobject> java_controller_;
#endif
+ // Set to true while processing an observer/callback and it's unsafe to
+ // delete the WebContents. This is not used for all callbacks, just the
+ // ones that we need to allow deletion from (such as completed/failed).
+ bool should_delay_web_contents_deletion_ = false;
+
base::WeakPtrFactory<NavigationControllerImpl> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(NavigationControllerImpl);
diff --git a/chromium/weblayer/browser/navigation_error_navigation_throttle.cc b/chromium/weblayer/browser/navigation_error_navigation_throttle.cc
new file mode 100644
index 00000000000..72fcf3c9406
--- /dev/null
+++ b/chromium/weblayer/browser/navigation_error_navigation_throttle.cc
@@ -0,0 +1,73 @@
+// Copyright 2020 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 "weblayer/browser/navigation_error_navigation_throttle.h"
+
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "net/base/net_errors.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+#include "weblayer/browser/navigation_controller_impl.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/common/error_page_helper.mojom.h"
+#include "weblayer/public/error_page.h"
+#include "weblayer/public/error_page_delegate.h"
+
+using content::NavigationThrottle;
+
+namespace weblayer {
+
+NavigationErrorNavigationThrottle::NavigationErrorNavigationThrottle(
+ content::NavigationHandle* handle)
+ : NavigationThrottle(handle) {
+ // As this calls to the delegate, and the delegate only knows about main
+ // frames, this should only be used for main frames.
+ DCHECK(handle->IsInMainFrame());
+}
+
+NavigationErrorNavigationThrottle::~NavigationErrorNavigationThrottle() =
+ default;
+
+NavigationThrottle::ThrottleCheckResult
+NavigationErrorNavigationThrottle::WillFailRequest() {
+ // The embedder is not allowed to replace ssl error pages.
+ if (navigation_handle()->GetNetErrorCode() == net::Error::OK ||
+ net::IsCertificateError(navigation_handle()->GetNetErrorCode())) {
+ return NavigationThrottle::PROCEED;
+ }
+
+ TabImpl* tab =
+ TabImpl::FromWebContents(navigation_handle()->GetWebContents());
+ // Instances of this class are only created if there is a Tab associated
+ // with the WebContents.
+ DCHECK(tab);
+ if (!tab->error_page_delegate())
+ return NavigationThrottle::PROCEED;
+
+ NavigationImpl* navigation =
+ static_cast<NavigationControllerImpl*>(tab->GetNavigationController())
+ ->GetNavigationImplFromHandle(navigation_handle());
+ // The navigation this was created for should always outlive this.
+ DCHECK(navigation);
+ auto error_page = tab->error_page_delegate()->GetErrorPageContent(navigation);
+ if (!error_page)
+ return NavigationThrottle::PROCEED;
+
+ mojo::AssociatedRemote<mojom::ErrorPageHelper> remote_error_page_helper;
+ navigation_handle()
+ ->GetRenderFrameHost()
+ ->GetRemoteAssociatedInterfaces()
+ ->GetInterface(&remote_error_page_helper);
+ remote_error_page_helper->DisableErrorPageHelperForNextError();
+
+ return NavigationThrottle::ThrottleCheckResult(
+ NavigationThrottle::BLOCK_REQUEST, navigation_handle()->GetNetErrorCode(),
+ error_page->html);
+}
+
+const char* NavigationErrorNavigationThrottle::GetNameForLogging() {
+ return "NavigationErrorNavigationThrottle";
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/navigation_error_navigation_throttle.h b/chromium/weblayer/browser/navigation_error_navigation_throttle.h
new file mode 100644
index 00000000000..0d70275234d
--- /dev/null
+++ b/chromium/weblayer/browser/navigation_error_navigation_throttle.h
@@ -0,0 +1,32 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_NAVIGATION_ERROR_NAVIGATION_THROTTLE_H_
+#define WEBLAYER_BROWSER_NAVIGATION_ERROR_NAVIGATION_THROTTLE_H_
+
+#include <memory>
+
+#include "content/public/browser/navigation_throttle.h"
+
+namespace weblayer {
+
+// NavigationThrottle implementation that allows the embedder to inject an
+// error page for non-ssl errors.
+class NavigationErrorNavigationThrottle : public content::NavigationThrottle {
+ public:
+ explicit NavigationErrorNavigationThrottle(content::NavigationHandle* handle);
+ NavigationErrorNavigationThrottle(const NavigationErrorNavigationThrottle&) =
+ delete;
+ NavigationErrorNavigationThrottle& operator=(
+ const NavigationErrorNavigationThrottle&) = delete;
+ ~NavigationErrorNavigationThrottle() override;
+
+ // content::NavigationThrottle:
+ ThrottleCheckResult WillFailRequest() override;
+ const char* GetNameForLogging() override;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_NAVIGATION_ERROR_NAVIGATION_THROTTLE_H_
diff --git a/chromium/weblayer/browser/navigation_error_navigation_throttle_browsertest.cc b/chromium/weblayer/browser/navigation_error_navigation_throttle_browsertest.cc
new file mode 100644
index 00000000000..3c3175f6904
--- /dev/null
+++ b/chromium/weblayer/browser/navigation_error_navigation_throttle_browsertest.cc
@@ -0,0 +1,94 @@
+// Copyright 2020 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 "weblayer/test/weblayer_browser_test.h"
+
+#include "base/optional.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "content/public/test/url_loader_interceptor.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/public/error_page.h"
+#include "weblayer/public/error_page_delegate.h"
+#include "weblayer/shell/browser/shell.h"
+#include "weblayer/test/test_navigation_observer.h"
+#include "weblayer/test/weblayer_browser_test_utils.h"
+
+#include "base/run_loop.h"
+
+namespace weblayer {
+
+namespace {
+
+class TestErrorPageDelegate : public ErrorPageDelegate {
+ public:
+ void set_error_page_content(const std::string& value) { content_ = value; }
+ // ErrorPageDelegate:
+ bool OnBackToSafety() override { return false; }
+ std::unique_ptr<ErrorPage> GetErrorPageContent(
+ Navigation* navigation) override {
+ if (!content_.has_value())
+ return nullptr;
+ auto error_page = std::make_unique<ErrorPage>();
+ error_page->html = *content_;
+ return error_page;
+ }
+
+ private:
+ base::Optional<std::string> content_;
+};
+
+} // namespace
+
+using NavigationErrorNavigationThrottleBrowserTest = WebLayerBrowserTest;
+
+// Verifies the delegate can inject an error page.
+IN_PROC_BROWSER_TEST_F(NavigationErrorNavigationThrottleBrowserTest,
+ InjectErrorPage) {
+ GURL url("http://doesntexist.com/foo");
+ auto interceptor = content::URLLoaderInterceptor::SetupRequestFailForURL(
+ url, net::ERR_NAME_NOT_RESOLVED);
+ TestErrorPageDelegate delegate;
+ delegate.set_error_page_content("<html><head><title>test error</title>");
+ shell()->tab()->SetErrorPageDelegate(&delegate);
+ NavigateAndWaitForFailure(url, shell());
+ EXPECT_EQ(base::ASCIIToUTF16("test error"), GetTitle(shell()));
+}
+
+// Verifies the delegate can inject an empty page.
+IN_PROC_BROWSER_TEST_F(NavigationErrorNavigationThrottleBrowserTest,
+ InjectEmptyErrorPage) {
+ GURL url("http://doesntexist.com/foo");
+ auto interceptor = content::URLLoaderInterceptor::SetupRequestFailForURL(
+ url, net::ERR_NAME_NOT_RESOLVED);
+ TestErrorPageDelegate delegate;
+ delegate.set_error_page_content(std::string());
+ shell()->tab()->SetErrorPageDelegate(&delegate);
+ NavigateAndWaitForFailure(url, shell());
+ base::Value body_text =
+ ExecuteScript(shell()->tab(), "document.body.textContent", false);
+ ASSERT_TRUE(body_text.is_string());
+ EXPECT_TRUE(body_text.GetString().empty());
+}
+
+// Verifies a null return value results in a default error page.
+// Network errors only have non-empty error pages on android.
+#if defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(NavigationErrorNavigationThrottleBrowserTest,
+ DefaultErrorPage) {
+ GURL url("http://doesntexist.com/foo");
+ auto interceptor = content::URLLoaderInterceptor::SetupRequestFailForURL(
+ url, net::ERR_NAME_NOT_RESOLVED);
+ TestErrorPageDelegate delegate;
+ shell()->tab()->SetErrorPageDelegate(&delegate);
+ NavigateAndWaitForFailure(url, shell());
+ base::Value body_text =
+ ExecuteScript(shell()->tab(), "document.body.textContent", false);
+ ASSERT_TRUE(body_text.is_string());
+ EXPECT_FALSE(body_text.GetString().empty());
+}
+#endif
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/navigation_impl.cc b/chromium/weblayer/browser/navigation_impl.cc
index e160069f225..a4cb6076eb0 100644
--- a/chromium/weblayer/browser/navigation_impl.cc
+++ b/chromium/weblayer/browser/navigation_impl.cc
@@ -9,7 +9,7 @@
#include "net/base/net_errors.h"
#include "net/http/http_util.h"
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
-#include "third_party/blink/public/mojom/referrer.mojom.h"
+#include "third_party/blink/public/mojom/loader/referrer.mojom.h"
#if defined(OS_ANDROID)
#include "base/android/jni_array.h"
@@ -88,6 +88,14 @@ jboolean NavigationImpl::SetUserAgentString(
#endif
+bool NavigationImpl::IsPageInitiated() {
+ return navigation_handle_->IsRendererInitiated();
+}
+
+bool NavigationImpl::IsReload() {
+ return navigation_handle_->GetReloadType() != content::ReloadType::NONE;
+}
+
GURL NavigationImpl::GetURL() {
return navigation_handle_->GetURL();
}
diff --git a/chromium/weblayer/browser/navigation_impl.h b/chromium/weblayer/browser/navigation_impl.h
index c002d887525..e3513458fe4 100644
--- a/chromium/weblayer/browser/navigation_impl.h
+++ b/chromium/weblayer/browser/navigation_impl.h
@@ -69,6 +69,8 @@ class NavigationImpl : public Navigation {
jboolean SetUserAgentString(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& value);
+ jboolean IsPageInitiated(JNIEnv* env) { return IsPageInitiated(); }
+ jboolean IsReload(JNIEnv* env) { return IsReload(); }
base::android::ScopedJavaGlobalRef<jobject> java_navigation() {
return java_navigation_;
@@ -89,6 +91,8 @@ class NavigationImpl : public Navigation {
void SetRequestHeader(const std::string& name,
const std::string& value) override;
void SetUserAgentString(const std::string& value) override;
+ bool IsPageInitiated() override;
+ bool IsReload() override;
content::NavigationHandle* navigation_handle_;
diff --git a/chromium/weblayer/browser/navigation_ui_data_impl.cc b/chromium/weblayer/browser/navigation_ui_data_impl.cc
new file mode 100644
index 00000000000..12435d2eaec
--- /dev/null
+++ b/chromium/weblayer/browser/navigation_ui_data_impl.cc
@@ -0,0 +1,20 @@
+// Copyright 2020 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 "weblayer/browser/navigation_ui_data_impl.h"
+
+namespace weblayer {
+
+NavigationUIDataImpl::NavigationUIDataImpl(
+ bool disable_network_error_auto_reload)
+ : disable_network_error_auto_reload_(disable_network_error_auto_reload) {}
+
+NavigationUIDataImpl::~NavigationUIDataImpl() = default;
+
+std::unique_ptr<content::NavigationUIData> NavigationUIDataImpl::Clone() {
+ return std::make_unique<NavigationUIDataImpl>(
+ disable_network_error_auto_reload_);
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/navigation_ui_data_impl.h b/chromium/weblayer/browser/navigation_ui_data_impl.h
new file mode 100644
index 00000000000..afd928ca576
--- /dev/null
+++ b/chromium/weblayer/browser/navigation_ui_data_impl.h
@@ -0,0 +1,34 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_NAVIGATION_UI_DATA_IMPL_H_
+#define WEBLAYER_BROWSER_NAVIGATION_UI_DATA_IMPL_H_
+
+#include "content/public/browser/navigation_ui_data.h"
+
+namespace weblayer {
+
+// Data that we pass to content::NavigationController::LoadURLWithParams
+// and can access from content::NavigationHandle later.
+class NavigationUIDataImpl : public content::NavigationUIData {
+ public:
+ explicit NavigationUIDataImpl(bool disable_network_error_auto_reload);
+ NavigationUIDataImpl(const NavigationUIDataImpl&) = delete;
+ NavigationUIDataImpl& operator=(const NavigationUIDataImpl&) = delete;
+ ~NavigationUIDataImpl() override;
+
+ // content::NavigationUIData implementation:
+ std::unique_ptr<content::NavigationUIData> Clone() override;
+
+ bool disable_network_error_auto_reload() const {
+ return disable_network_error_auto_reload_;
+ }
+
+ private:
+ bool disable_network_error_auto_reload_;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_NAVIGATION_UI_DATA_IMPL_H_
diff --git a/chromium/weblayer/browser/no_state_prefetch/no_state_prefetch_browsertest.cc b/chromium/weblayer/browser/no_state_prefetch/no_state_prefetch_browsertest.cc
new file mode 100644
index 00000000000..03e5d9af1c5
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/no_state_prefetch_browsertest.cc
@@ -0,0 +1,212 @@
+// Copyright 2020 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 <memory>
+
+#include "base/run_loop.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+#include "components/prerender/browser/prerender_histograms.h"
+#include "components/prerender/browser/prerender_manager.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/url_loader_monitor.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "weblayer/browser/no_state_prefetch/prerender_link_manager_factory.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
+#include "weblayer/browser/profile_impl.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/shell/browser/shell.h"
+#include "weblayer/test/weblayer_browser_test.h"
+#include "weblayer/test/weblayer_browser_test_utils.h"
+
+#if defined(OS_ANDROID)
+#include "components/ukm/test_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "weblayer/browser/android/metrics/metrics_test_helper.h"
+#endif
+
+namespace weblayer {
+
+class NoStatePrefetchBrowserTest : public WebLayerBrowserTest {
+ public:
+#if defined(OS_ANDROID)
+ void SetUp() override {
+ InstallTestGmsBridge(/* user_consent= */ true);
+
+ WebLayerBrowserTest::SetUp();
+ }
+
+ void TearDown() override {
+ RemoveTestGmsBridge();
+ WebLayerBrowserTest::TearDown();
+ }
+#endif
+
+ void SetUpOnMainThread() override {
+ prerendered_page_fetched_ = std::make_unique<base::RunLoop>();
+ script_resource_fetched_ = std::make_unique<base::RunLoop>();
+
+ https_server_ = std::make_unique<net::EmbeddedTestServer>(
+ net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server_->RegisterRequestHandler(base::BindRepeating(
+ &NoStatePrefetchBrowserTest::HandleRequest, base::Unretained(this)));
+ https_server_->AddDefaultHandlers(
+ base::FilePath(FILE_PATH_LITERAL("weblayer/test/data")));
+ ASSERT_TRUE(https_server_->Start());
+
+#if defined(OS_ANDROID)
+ ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
+#endif
+ }
+
+ // Helper methods.
+ std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
+ const net::test_server::HttpRequest& request) {
+ if (request.GetURL().path().find("prerendered_page") != std::string::npos) {
+ if (prerendered_page_fetched_)
+ prerendered_page_fetched_->Quit();
+ }
+ if (request.GetURL().path().find("prefetch.js") != std::string::npos) {
+ script_fetched_ = true;
+ auto iter = request.headers.find("Purpose");
+ purpose_header_value_ = iter->second;
+ if (script_resource_fetched_)
+ script_resource_fetched_->Quit();
+ }
+ if (request.GetURL().path().find("prefetch_meta.js") != std::string::npos) {
+ script_executed_ = true;
+ }
+ if (request.GetURL().path().find("alert.html") != std::string::npos) {
+ link_rel_next_started_ = true;
+ }
+
+ // The default handlers will take care of this request.
+ return nullptr;
+ }
+
+ void NavigateToPageAndWaitForTitleChange(const GURL& navigate_to,
+ base::string16 expected_title) {
+ content::TitleWatcher title_watcher(
+ static_cast<TabImpl*>(shell()->tab())->web_contents(), expected_title);
+ NavigateAndWaitForCompletion(navigate_to, shell());
+ ASSERT_TRUE(expected_title == title_watcher.WaitAndGetTitle());
+ }
+
+ protected:
+ content::BrowserContext* GetBrowserContext() {
+ Tab* tab = shell()->tab();
+ TabImpl* tab_impl = static_cast<TabImpl*>(tab);
+ return tab_impl->web_contents()->GetBrowserContext();
+ }
+
+ std::unique_ptr<base::RunLoop> prerendered_page_fetched_;
+ std::unique_ptr<base::RunLoop> script_resource_fetched_;
+ bool link_rel_next_started_ = false;
+ bool script_fetched_ = false;
+ bool script_executed_ = false;
+ std::string purpose_header_value_;
+ std::unique_ptr<net::EmbeddedTestServer> https_server_;
+#if defined(OS_ANDROID)
+ std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_;
+#endif
+};
+
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, CreatePrerenderManager) {
+ auto* prerender_manager =
+ PrerenderManagerFactory::GetForBrowserContext(GetBrowserContext());
+ EXPECT_TRUE(prerender_manager);
+}
+
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, CreatePrerenderLinkManager) {
+ auto* prerender_link_manager =
+ PrerenderLinkManagerFactory::GetForBrowserContext(GetBrowserContext());
+ EXPECT_TRUE(prerender_link_manager);
+}
+
+// Test that adding a link-rel prerender tag causes a fetch.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest,
+ LinkRelPrerenderPageFetched) {
+ NavigateAndWaitForCompletion(GURL(https_server_->GetURL("/parent_page.html")),
+ shell());
+ prerendered_page_fetched_->Run();
+}
+
+// Test that only render blocking resources are loaded during NoStatePrefetch.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest,
+ NSPLoadsRenderBlockingResource) {
+ NavigateAndWaitForCompletion(GURL(https_server_->GetURL("/parent_page.html")),
+ shell());
+ script_resource_fetched_->Run();
+ EXPECT_EQ("prefetch", purpose_header_value_);
+ EXPECT_FALSE(script_executed_);
+}
+
+// Test that navigating to a no-state-prefetched page executes JS and reuses
+// prerendered resources.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, NavigateToPrerenderedPage) {
+ NavigateAndWaitForCompletion(GURL(https_server_->GetURL("/parent_page.html")),
+ shell());
+ script_resource_fetched_->Run();
+
+ // Navigate to the prerendered page and wait for its title to change.
+ script_fetched_ = false;
+ NavigateToPageAndWaitForTitleChange(
+ GURL(https_server_->GetURL("/prerendered_page.html")),
+ base::ASCIIToUTF16("Prefetch Page"));
+
+ EXPECT_FALSE(script_fetched_);
+ EXPECT_TRUE(script_executed_);
+}
+
+#if defined(OS_ANDROID)
+// Test that no-state-prefetch results in UKM getting recorded.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, UKMRecorded) {
+ GetProfile()->SetBooleanSetting(SettingType::UKM_ENABLED, true);
+ NavigateAndWaitForCompletion(GURL(https_server_->GetURL("/parent_page.html")),
+ shell());
+ script_resource_fetched_->Run();
+
+ NavigateToPageAndWaitForTitleChange(
+ GURL(https_server_->GetURL("/prerendered_page.html")),
+ base::ASCIIToUTF16("Prefetch Page"));
+
+ auto entries = ukm_recorder_->GetEntriesByName(
+ ukm::builders::NoStatePrefetch::kEntryName);
+ ASSERT_EQ(entries.size(), 1u);
+ const auto* entry = entries[0];
+ // FinalStatus must be set to FINAL_STATUS_NOSTATE_PREFETCH_FINISHED.
+ ukm_recorder_->ExpectEntryMetric(
+ entry,
+ ukm::builders::NoStatePrefetch::kPrefetchedRecently_FinalStatusName, 56);
+ // Origin must be set to ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN.
+ ukm_recorder_->ExpectEntryMetric(
+ entry, ukm::builders::NoStatePrefetch::kPrefetchedRecently_OriginName, 7);
+}
+#endif
+
+// link-rel="prerender" happens even when NoStatePrefetch has been disabled.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest,
+ LinkRelPrerenderWithNSPDisabled) {
+ GetProfile()->SetBooleanSetting(SettingType::NETWORK_PREDICTION_ENABLED,
+ false);
+ NavigateAndWaitForCompletion(GURL(https_server_->GetURL("/parent_page.html")),
+ shell());
+ prerendered_page_fetched_->Run();
+}
+
+// link-rel="next" doesn't happen when NoStatePrefetch has been disabled.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, LinkRelNextWithNSPDisabled) {
+ GetProfile()->SetBooleanSetting(SettingType::NETWORK_PREDICTION_ENABLED,
+ false);
+ NavigateToPageAndWaitForTitleChange(
+ GURL(https_server_->GetURL("/parent_page.html")),
+ base::ASCIIToUTF16("Parent Page"));
+ EXPECT_FALSE(link_rel_next_started_);
+}
+
+} // namespace weblayer \ No newline at end of file
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_link_manager_factory.cc b/chromium/weblayer/browser/no_state_prefetch/prerender_link_manager_factory.cc
new file mode 100644
index 00000000000..d7f715628e3
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_link_manager_factory.cc
@@ -0,0 +1,51 @@
+// Copyright 2020 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 "weblayer/browser/no_state_prefetch/prerender_link_manager_factory.h"
+
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/prerender/browser/prerender_link_manager.h"
+#include "components/prerender/browser/prerender_manager.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
+
+namespace weblayer {
+
+// static
+prerender::PrerenderLinkManager*
+PrerenderLinkManagerFactory::GetForBrowserContext(
+ content::BrowserContext* browser_context) {
+ return static_cast<prerender::PrerenderLinkManager*>(
+ GetInstance()->GetServiceForBrowserContext(browser_context, true));
+}
+
+// static
+PrerenderLinkManagerFactory* PrerenderLinkManagerFactory::GetInstance() {
+ return base::Singleton<PrerenderLinkManagerFactory>::get();
+}
+
+PrerenderLinkManagerFactory::PrerenderLinkManagerFactory()
+ : BrowserContextKeyedServiceFactory(
+ "PrerenderLinkmanager",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(weblayer::PrerenderManagerFactory::GetInstance());
+}
+
+KeyedService* PrerenderLinkManagerFactory::BuildServiceInstanceFor(
+ content::BrowserContext* browser_context) const {
+ DCHECK(browser_context);
+
+ prerender::PrerenderManager* prerender_manager =
+ PrerenderManagerFactory::GetForBrowserContext(browser_context);
+ if (!prerender_manager)
+ return nullptr;
+
+ return new prerender::PrerenderLinkManager(prerender_manager);
+}
+
+content::BrowserContext* PrerenderLinkManagerFactory::GetBrowserContextToUse(
+ content::BrowserContext* browser_context) const {
+ return browser_context;
+}
+
+} // namespace weblayer \ No newline at end of file
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_link_manager_factory.h b/chromium/weblayer/browser/no_state_prefetch/prerender_link_manager_factory.h
new file mode 100644
index 00000000000..7369249c063
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_link_manager_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_LINK_MANAGER_FACTORY_H_
+#define WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_LINK_MANAGER_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "components/prerender/browser/prerender_link_manager.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace weblayer {
+
+class PrerenderLinkManagerFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ // Returns the prerender::PrerenderLinkManager for |context|.
+ static prerender::PrerenderLinkManager* GetForBrowserContext(
+ content::BrowserContext* context);
+
+ static PrerenderLinkManagerFactory* GetInstance();
+
+ private:
+ friend struct base::DefaultSingletonTraits<PrerenderLinkManagerFactory>;
+
+ PrerenderLinkManagerFactory();
+ ~PrerenderLinkManagerFactory() override = default;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* browser) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_LINK_MANAGER_FACTORY_H_
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.cc b/chromium/weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.cc
new file mode 100644
index 00000000000..7194cdb225e
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.cc
@@ -0,0 +1,45 @@
+// Copyright 2020 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 "weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.h"
+
+#include "components/prerender/browser/prerender_contents_delegate.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "weblayer/browser/browser_context_impl.h"
+#include "weblayer/browser/cookie_settings_factory.h"
+#include "weblayer/browser/profile_impl.h"
+#include "weblayer/public/profile.h"
+
+namespace weblayer {
+
+PrerenderManagerDelegateImpl::PrerenderManagerDelegateImpl(
+ content::BrowserContext* browser_context)
+ : browser_context_(browser_context) {}
+
+scoped_refptr<content_settings::CookieSettings>
+PrerenderManagerDelegateImpl::GetCookieSettings() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ return CookieSettingsFactory::GetForBrowserContext(browser_context_);
+}
+
+std::unique_ptr<prerender::PrerenderContentsDelegate>
+PrerenderManagerDelegateImpl::GetPrerenderContentsDelegate() {
+ return std::make_unique<prerender::PrerenderContentsDelegate>();
+}
+
+bool PrerenderManagerDelegateImpl::IsNetworkPredictionPreferenceEnabled() {
+ auto* profile = ProfileImpl::FromBrowserContext(browser_context_);
+ DCHECK(profile);
+
+ return profile->GetBooleanSetting(SettingType::NETWORK_PREDICTION_ENABLED);
+}
+
+std::string PrerenderManagerDelegateImpl::GetReasonForDisablingPrediction() {
+ return IsNetworkPredictionPreferenceEnabled() ? ""
+ : "Disabled by user setting";
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.h b/chromium/weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.h
new file mode 100644
index 00000000000..788a8cad121
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.h
@@ -0,0 +1,37 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_MANAGER_DELEGATE_IMPL_H_
+#define WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_MANAGER_DELEGATE_IMPL_H_
+
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/prerender/browser/prerender_manager_delegate.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace weblayer {
+
+class PrerenderManagerDelegateImpl
+ : public prerender::PrerenderManagerDelegate {
+ public:
+ explicit PrerenderManagerDelegateImpl(
+ content::BrowserContext* browser_context);
+ ~PrerenderManagerDelegateImpl() override = default;
+
+ // PrerenderManagerDelegate overrides.
+ scoped_refptr<content_settings::CookieSettings> GetCookieSettings() override;
+ std::unique_ptr<prerender::PrerenderContentsDelegate>
+ GetPrerenderContentsDelegate() override;
+ bool IsNetworkPredictionPreferenceEnabled() override;
+ std::string GetReasonForDisablingPrediction() override;
+
+ private:
+ content::BrowserContext* browser_context_;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_MANAGER_DELEGATE_IMPL_H_
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_manager_factory.cc b/chromium/weblayer/browser/no_state_prefetch/prerender_manager_factory.cc
new file mode 100644
index 00000000000..b99e036662f
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_manager_factory.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 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 "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
+
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/prerender/browser/prerender_manager.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_delegate_impl.h"
+
+namespace weblayer {
+
+// static
+prerender::PrerenderManager* PrerenderManagerFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<prerender::PrerenderManager*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+PrerenderManagerFactory* PrerenderManagerFactory::GetInstance() {
+ return base::Singleton<PrerenderManagerFactory>::get();
+}
+
+PrerenderManagerFactory::PrerenderManagerFactory()
+ : BrowserContextKeyedServiceFactory(
+ "PrerenderManager",
+ BrowserContextDependencyManager::GetInstance()) {}
+
+KeyedService* PrerenderManagerFactory::BuildServiceInstanceFor(
+ content::BrowserContext* browser_context) const {
+ return new prerender::PrerenderManager(
+ browser_context,
+ std::make_unique<PrerenderManagerDelegateImpl>(browser_context));
+}
+
+content::BrowserContext* PrerenderManagerFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return context;
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_manager_factory.h b/chromium/weblayer/browser/no_state_prefetch/prerender_manager_factory.h
new file mode 100644
index 00000000000..1587d0bf759
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_manager_factory.h
@@ -0,0 +1,47 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_MANAGER_FACTORY_H_
+#define WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_MANAGER_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace prerender {
+class PrerenderManager;
+}
+
+namespace weblayer {
+
+// Singleton that owns all PrerenderManagers and associates them with
+// BrowserContexts. Listens for the BrowserContext's destruction notification
+// and cleans up the associated PrerenderManager.
+class PrerenderManagerFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ // Returns the PrerenderManager for |context|.
+ static prerender::PrerenderManager* GetForBrowserContext(
+ content::BrowserContext* context);
+
+ static PrerenderManagerFactory* GetInstance();
+
+ private:
+ friend struct base::DefaultSingletonTraits<PrerenderManagerFactory>;
+
+ PrerenderManagerFactory();
+ ~PrerenderManagerFactory() override = default;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* browser) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_MANAGER_FACTORY_H_
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.cc b/chromium/weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.cc
new file mode 100644
index 00000000000..1bc7022b279
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.cc
@@ -0,0 +1,19 @@
+// Copyright 2020 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 "weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.h"
+
+#include "components/prerender/browser/prerender_link_manager.h"
+#include "content/public/browser/browser_context.h"
+#include "weblayer/browser/no_state_prefetch/prerender_link_manager_factory.h"
+
+namespace weblayer {
+
+prerender::PrerenderLinkManager*
+PrerenderProcessorImplDelegateImpl::GetPrerenderLinkManager(
+ content::BrowserContext* browser_context) {
+ return PrerenderLinkManagerFactory::GetForBrowserContext(browser_context);
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.h b/chromium/weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.h
new file mode 100644
index 00000000000..1221e85b2da
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.h
@@ -0,0 +1,33 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_PROCESSOR_IMPL_DELEGATE_IMPL_H_
+#define WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_PROCESSOR_IMPL_DELEGATE_IMPL_H_
+
+#include "components/prerender/browser/prerender_processor_impl_delegate.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace prerender {
+class PrerenderLinkManager;
+}
+
+namespace weblayer {
+
+class PrerenderProcessorImplDelegateImpl
+ : public prerender::PrerenderProcessorImplDelegate {
+ public:
+ PrerenderProcessorImplDelegateImpl() = default;
+ ~PrerenderProcessorImplDelegateImpl() override = default;
+
+ // prerender::PrerenderProcessorImplDelegate overrides,
+ prerender::PrerenderLinkManager* GetPrerenderLinkManager(
+ content::BrowserContext* browser_context) override;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_PROCESSOR_IMPL_DELEGATE_IMPL_H_
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_tab_helper.cc b/chromium/weblayer/browser/no_state_prefetch/prerender_tab_helper.cc
new file mode 100644
index 00000000000..3b2d204df1f
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_tab_helper.cc
@@ -0,0 +1,37 @@
+// Copyright 2020 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 "weblayer/browser/no_state_prefetch/prerender_tab_helper.h"
+
+#include "components/prerender/browser/prerender_manager.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
+
+namespace weblayer {
+
+PrerenderTabHelper::PrerenderTabHelper(content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents) {}
+
+PrerenderTabHelper::~PrerenderTabHelper() = default;
+
+void PrerenderTabHelper::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (!navigation_handle->IsInMainFrame() ||
+ !navigation_handle->HasCommitted() || navigation_handle->IsErrorPage()) {
+ return;
+ }
+
+ prerender::PrerenderManager* prerender_manager =
+ PrerenderManagerFactory::GetForBrowserContext(
+ web_contents()->GetBrowserContext());
+
+ if (prerender_manager &&
+ !prerender_manager->IsWebContentsPrerendering(web_contents(), nullptr))
+ prerender_manager->RecordNavigation(navigation_handle->GetURL());
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(PrerenderTabHelper)
+
+} // namespace weblayer \ No newline at end of file
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_tab_helper.h b/chromium/weblayer/browser/no_state_prefetch/prerender_tab_helper.h
new file mode 100644
index 00000000000..996abda8233
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_tab_helper.h
@@ -0,0 +1,45 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_TAB_HELPER_H_
+#define WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_TAB_HELPER_H_
+
+#include "base/macros.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace prerender {
+class PrerenderManager;
+}
+
+namespace weblayer {
+
+// Notifies the prerender::PrerenderManager with the events happening in the
+// prerendered WebContents.
+class PrerenderTabHelper
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<PrerenderTabHelper> {
+ public:
+ ~PrerenderTabHelper() override;
+ PrerenderTabHelper(const PrerenderTabHelper&) = delete;
+ PrerenderTabHelper& operator=(const PrerenderTabHelper&) = delete;
+
+ // content::WebContentsObserver implementation.
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+
+ private:
+ explicit PrerenderTabHelper(content::WebContents* web_contents);
+ friend class content::WebContentsUserData<PrerenderTabHelper>;
+
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_TAB_HELPER_H_ \ No newline at end of file
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_utils.cc b/chromium/weblayer/browser/no_state_prefetch/prerender_utils.cc
new file mode 100644
index 00000000000..177a16adbea
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_utils.cc
@@ -0,0 +1,27 @@
+// Copyright 2020 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 "weblayer/browser/no_state_prefetch/prerender_utils.h"
+
+#include "components/prerender/browser/prerender_contents.h"
+#include "components/prerender/browser/prerender_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
+
+namespace weblayer {
+prerender::PrerenderContents* PrerenderContentsFromWebContents(
+ content::WebContents* web_contents) {
+ if (!web_contents)
+ return nullptr;
+
+ prerender::PrerenderManager* prerender_manager =
+ PrerenderManagerFactory::GetForBrowserContext(
+ web_contents->GetBrowserContext());
+ if (!prerender_manager)
+ return nullptr;
+
+ return prerender_manager->GetPrerenderContents(web_contents);
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/no_state_prefetch/prerender_utils.h b/chromium/weblayer/browser/no_state_prefetch/prerender_utils.h
new file mode 100644
index 00000000000..5064e6f1321
--- /dev/null
+++ b/chromium/weblayer/browser/no_state_prefetch/prerender_utils.h
@@ -0,0 +1,23 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_UTILS_H_
+#define WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_UTILS_H_
+
+namespace content {
+class WebContents;
+}
+
+namespace prerender {
+class PrerenderContents;
+}
+
+namespace weblayer {
+
+prerender::PrerenderContents* PrerenderContentsFromWebContents(
+ content::WebContents* web_contents);
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_NO_STATE_PREFETCH_PRERENDER_UTILS_H_
diff --git a/chromium/weblayer/browser/page_load_metrics_initialize.cc b/chromium/weblayer/browser/page_load_metrics_initialize.cc
index cb2978f8951..740b83fd1c8 100644
--- a/chromium/weblayer/browser/page_load_metrics_initialize.cc
+++ b/chromium/weblayer/browser/page_load_metrics_initialize.cc
@@ -7,6 +7,10 @@
#include "base/macros.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "components/page_load_metrics/browser/page_load_metrics_embedder_base.h"
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+#include "components/page_load_metrics/browser/page_load_tracker.h"
+#include "weblayer/browser/no_state_prefetch/prerender_utils.h"
+#include "weblayer/browser/ukm_page_load_metrics_observer.h"
namespace weblayer {
@@ -27,7 +31,7 @@ class PageLoadMetricsEmbedder
// page_load_metrics::PageLoadMetricsEmbedderBase:
bool IsNewTabPageUrl(const GURL& url) override { return false; }
bool IsPrerender(content::WebContents* web_contents) override {
- return false;
+ return PrerenderContentsFromWebContents(web_contents);
}
bool IsExtensionUrl(const GURL& url) override { return false; }
@@ -35,10 +39,17 @@ class PageLoadMetricsEmbedder
// page_load_metrics::PageLoadMetricsEmbedderBase:
void RegisterEmbedderObservers(
page_load_metrics::PageLoadTracker* tracker) override {
+ std::unique_ptr<page_load_metrics::PageLoadMetricsObserver> ukm_observer =
+ UkmPageLoadMetricsObserver::CreateIfNeeded();
+ if (ukm_observer)
+ tracker->AddObserver(std::move(ukm_observer));
+
if (g_callback_for_testing)
(*g_callback_for_testing).Run(tracker);
}
- bool IsPrerendering() const override { return false; }
+ bool IsPrerendering() const override {
+ return PrerenderContentsFromWebContents(web_contents());
+ }
};
} // namespace
diff --git a/chromium/weblayer/browser/tab_specific_content_settings_delegate.cc b/chromium/weblayer/browser/page_specific_content_settings_delegate.cc
index 13c9c791d74..4a18513b7d7 100644
--- a/chromium/weblayer/browser/tab_specific_content_settings_delegate.cc
+++ b/chromium/weblayer/browser/page_specific_content_settings_delegate.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "weblayer/browser/tab_specific_content_settings_delegate.h"
+#include "weblayer/browser/page_specific_content_settings_delegate.h"
#include "base/bind_helpers.h"
#include "components/content_settings/core/common/content_settings.h"
@@ -25,15 +25,15 @@ void SetContentSettingRules(content::RenderProcessHost* process,
} // namespace
-TabSpecificContentSettingsDelegate::TabSpecificContentSettingsDelegate(
+PageSpecificContentSettingsDelegate::PageSpecificContentSettingsDelegate(
content::WebContents* web_contents)
: web_contents_(web_contents) {}
-TabSpecificContentSettingsDelegate::~TabSpecificContentSettingsDelegate() =
+PageSpecificContentSettingsDelegate::~PageSpecificContentSettingsDelegate() =
default;
// static
-void TabSpecificContentSettingsDelegate::UpdateRendererContentSettingRules(
+void PageSpecificContentSettingsDelegate::UpdateRendererContentSettingRules(
content::RenderProcessHost* process) {
RendererContentSettingRules rules;
GetRendererContentSettingRules(
@@ -43,25 +43,25 @@ void TabSpecificContentSettingsDelegate::UpdateRendererContentSettingRules(
weblayer::SetContentSettingRules(process, rules);
}
-void TabSpecificContentSettingsDelegate::UpdateLocationBar() {}
+void PageSpecificContentSettingsDelegate::UpdateLocationBar() {}
-void TabSpecificContentSettingsDelegate::SetContentSettingRules(
+void PageSpecificContentSettingsDelegate::SetContentSettingRules(
content::RenderProcessHost* process,
const RendererContentSettingRules& rules) {
weblayer::SetContentSettingRules(process, rules);
}
-PrefService* TabSpecificContentSettingsDelegate::GetPrefs() {
+PrefService* PageSpecificContentSettingsDelegate::GetPrefs() {
return static_cast<BrowserContextImpl*>(web_contents_->GetBrowserContext())
->pref_service();
}
-HostContentSettingsMap* TabSpecificContentSettingsDelegate::GetSettingsMap() {
+HostContentSettingsMap* PageSpecificContentSettingsDelegate::GetSettingsMap() {
return HostContentSettingsMapFactory::GetForBrowserContext(
web_contents_->GetBrowserContext());
}
-ContentSetting TabSpecificContentSettingsDelegate::GetEmbargoSetting(
+ContentSetting PageSpecificContentSettingsDelegate::GetEmbargoSetting(
const GURL& request_origin,
ContentSettingsType permission) {
return PermissionDecisionAutoBlockerFactory::GetForBrowserContext(
@@ -71,30 +71,51 @@ ContentSetting TabSpecificContentSettingsDelegate::GetEmbargoSetting(
}
std::vector<storage::FileSystemType>
-TabSpecificContentSettingsDelegate::GetAdditionalFileSystemTypes() {
+PageSpecificContentSettingsDelegate::GetAdditionalFileSystemTypes() {
return {};
}
browsing_data::CookieHelper::IsDeletionDisabledCallback
-TabSpecificContentSettingsDelegate::GetIsDeletionDisabledCallback() {
+PageSpecificContentSettingsDelegate::GetIsDeletionDisabledCallback() {
return base::NullCallback();
}
-bool TabSpecificContentSettingsDelegate::IsMicrophoneCameraStateChanged(
- content_settings::TabSpecificContentSettings::MicrophoneCameraState
+bool PageSpecificContentSettingsDelegate::IsMicrophoneCameraStateChanged(
+ content_settings::PageSpecificContentSettings::MicrophoneCameraState
microphone_camera_state,
const std::string& media_stream_selected_audio_device,
const std::string& media_stream_selected_video_device) {
return false;
}
-content_settings::TabSpecificContentSettings::MicrophoneCameraState
-TabSpecificContentSettingsDelegate::GetMicrophoneCameraState() {
- return content_settings::TabSpecificContentSettings::
+content_settings::PageSpecificContentSettings::MicrophoneCameraState
+PageSpecificContentSettingsDelegate::GetMicrophoneCameraState() {
+ return content_settings::PageSpecificContentSettings::
MICROPHONE_CAMERA_NOT_ACCESSED;
}
-void TabSpecificContentSettingsDelegate::OnContentBlocked(
+void PageSpecificContentSettingsDelegate::OnContentBlocked(
ContentSettingsType type) {}
+void PageSpecificContentSettingsDelegate::OnCacheStorageAccessAllowed(
+ const url::Origin& origin) {}
+
+void PageSpecificContentSettingsDelegate::OnCookieAccessAllowed(
+ const net::CookieList& accessed_cookies) {}
+
+void PageSpecificContentSettingsDelegate::OnDomStorageAccessAllowed(
+ const url::Origin& origin) {}
+
+void PageSpecificContentSettingsDelegate::OnFileSystemAccessAllowed(
+ const url::Origin& origin) {}
+
+void PageSpecificContentSettingsDelegate::OnIndexedDBAccessAllowed(
+ const url::Origin& origin) {}
+
+void PageSpecificContentSettingsDelegate::OnServiceWorkerAccessAllowed(
+ const url::Origin& origin) {}
+
+void PageSpecificContentSettingsDelegate::OnWebDatabaseAccessAllowed(
+ const url::Origin& origin) {}
+
} // namespace weblayer
diff --git a/chromium/weblayer/browser/page_specific_content_settings_delegate.h b/chromium/weblayer/browser/page_specific_content_settings_delegate.h
new file mode 100644
index 00000000000..8ebdac3d85d
--- /dev/null
+++ b/chromium/weblayer/browser/page_specific_content_settings_delegate.h
@@ -0,0 +1,61 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_PAGE_SPECIFIC_CONTENT_SETTINGS_DELEGATE_H_
+#define WEBLAYER_BROWSER_PAGE_SPECIFIC_CONTENT_SETTINGS_DELEGATE_H_
+
+#include "components/content_settings/browser/page_specific_content_settings.h"
+
+namespace weblayer {
+
+// Called by PageSpecificContentSettings to handle WebLayer specific logic.
+class PageSpecificContentSettingsDelegate
+ : public content_settings::PageSpecificContentSettings::Delegate {
+ public:
+ explicit PageSpecificContentSettingsDelegate(
+ content::WebContents* web_contents);
+ ~PageSpecificContentSettingsDelegate() override;
+ PageSpecificContentSettingsDelegate(
+ const PageSpecificContentSettingsDelegate&) = delete;
+ PageSpecificContentSettingsDelegate& operator=(
+ const PageSpecificContentSettingsDelegate&) = delete;
+
+ static void UpdateRendererContentSettingRules(
+ content::RenderProcessHost* process);
+
+ private:
+ // PageSpecificContentSettings::Delegate:
+ void UpdateLocationBar() override;
+ void SetContentSettingRules(
+ content::RenderProcessHost* process,
+ const RendererContentSettingRules& rules) override;
+ PrefService* GetPrefs() override;
+ HostContentSettingsMap* GetSettingsMap() override;
+ ContentSetting GetEmbargoSetting(const GURL& request_origin,
+ ContentSettingsType permission) override;
+ std::vector<storage::FileSystemType> GetAdditionalFileSystemTypes() override;
+ browsing_data::CookieHelper::IsDeletionDisabledCallback
+ GetIsDeletionDisabledCallback() override;
+ bool IsMicrophoneCameraStateChanged(
+ content_settings::PageSpecificContentSettings::MicrophoneCameraState
+ microphone_camera_state,
+ const std::string& media_stream_selected_audio_device,
+ const std::string& media_stream_selected_video_device) override;
+ content_settings::PageSpecificContentSettings::MicrophoneCameraState
+ GetMicrophoneCameraState() override;
+ void OnContentBlocked(ContentSettingsType type) override;
+ void OnCacheStorageAccessAllowed(const url::Origin& origin) override;
+ void OnCookieAccessAllowed(const net::CookieList& accessed_cookies) override;
+ void OnDomStorageAccessAllowed(const url::Origin& origin) override;
+ void OnFileSystemAccessAllowed(const url::Origin& origin) override;
+ void OnIndexedDBAccessAllowed(const url::Origin& origin) override;
+ void OnServiceWorkerAccessAllowed(const url::Origin& origin) override;
+ void OnWebDatabaseAccessAllowed(const url::Origin& origin) override;
+
+ content::WebContents* web_contents_;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_PAGE_SPECIFIC_CONTENT_SETTINGS_DELEGATE_H_
diff --git a/chromium/weblayer/browser/permissions/geolocation_permission_context_delegate.cc b/chromium/weblayer/browser/permissions/geolocation_permission_context_delegate.cc
index 27e7a80898b..381eef27258 100644
--- a/chromium/weblayer/browser/permissions/geolocation_permission_context_delegate.cc
+++ b/chromium/weblayer/browser/permissions/geolocation_permission_context_delegate.cc
@@ -5,6 +5,7 @@
#include "weblayer/browser/permissions/geolocation_permission_context_delegate.h"
#include "build/build_config.h"
+#include "weblayer/browser/default_search_engine.h"
#if defined(OS_ANDROID)
#include "weblayer/browser/android/permission_request_utils.h"
@@ -39,8 +40,8 @@ PrefService* GeolocationPermissionContextDelegate::GetPrefs(
bool GeolocationPermissionContextDelegate::IsRequestingOriginDSE(
content::BrowserContext* browser_context,
const GURL& requesting_origin) {
- // TODO(crbug.com/1063433): This may need to be implemented for phase 3.
- return false;
+ return IsPermissionControlledByDse(ContentSettingsType::GEOLOCATION,
+ url::Origin::Create(requesting_origin));
}
void GeolocationPermissionContextDelegate::FinishNotifyPermissionSet(
diff --git a/chromium/weblayer/browser/permissions/weblayer_permissions_client.cc b/chromium/weblayer/browser/permissions/weblayer_permissions_client.cc
index e2fb5ff077e..24a2d10f0dc 100644
--- a/chromium/weblayer/browser/permissions/weblayer_permissions_client.cc
+++ b/chromium/weblayer/browser/permissions/weblayer_permissions_client.cc
@@ -6,6 +6,7 @@
#include "components/content_settings/core/browser/cookie_settings.h"
#include "weblayer/browser/cookie_settings_factory.h"
+#include "weblayer/browser/default_search_engine.h"
#include "weblayer/browser/host_content_settings_map_factory.h"
#include "weblayer/browser/permissions/permission_decision_auto_blocker_factory.h"
#include "weblayer/browser/permissions/permission_manager_factory.h"
@@ -34,6 +35,14 @@ WebLayerPermissionsClient::GetCookieSettings(
return CookieSettingsFactory::GetForBrowserContext(browser_context);
}
+bool WebLayerPermissionsClient::IsSubresourceFilterActivated(
+ content::BrowserContext* browser_context,
+ const GURL& url) {
+ // As the web layer does not currently support subresource filtering, the
+ // activation setting does not change any browser behavior.
+ return false;
+}
+
permissions::PermissionDecisionAutoBlocker*
WebLayerPermissionsClient::GetPermissionDecisionAutoBlocker(
content::BrowserContext* browser_context) {
@@ -53,6 +62,24 @@ permissions::ChooserContextBase* WebLayerPermissionsClient::GetChooserContext(
}
#if defined(OS_ANDROID)
+bool WebLayerPermissionsClient::IsPermissionControlledByDse(
+ content::BrowserContext* browser_context,
+ ContentSettingsType type,
+ const url::Origin& origin) {
+ return weblayer::IsPermissionControlledByDse(type, origin);
+}
+
+bool WebLayerPermissionsClient::ResetPermissionIfControlledByDse(
+ content::BrowserContext* browser_context,
+ ContentSettingsType type,
+ const url::Origin& origin) {
+ if (IsPermissionControlledByDse(browser_context, type, origin)) {
+ ResetDsePermissions(browser_context);
+ return true;
+ }
+ return false;
+}
+
void WebLayerPermissionsClient::RepromptForAndroidPermissions(
content::WebContents* web_contents,
const std::vector<ContentSettingsType>& content_settings_types,
diff --git a/chromium/weblayer/browser/permissions/weblayer_permissions_client.h b/chromium/weblayer/browser/permissions/weblayer_permissions_client.h
index 8bcc5dbc215..79042ef9649 100644
--- a/chromium/weblayer/browser/permissions/weblayer_permissions_client.h
+++ b/chromium/weblayer/browser/permissions/weblayer_permissions_client.h
@@ -24,6 +24,8 @@ class WebLayerPermissionsClient : public permissions::PermissionsClient {
content::BrowserContext* browser_context) override;
scoped_refptr<content_settings::CookieSettings> GetCookieSettings(
content::BrowserContext* browser_context) override;
+ bool IsSubresourceFilterActivated(content::BrowserContext* browser_context,
+ const GURL& url) override;
permissions::PermissionDecisionAutoBlocker* GetPermissionDecisionAutoBlocker(
content::BrowserContext* browser_context) override;
permissions::PermissionManager* GetPermissionManager(
@@ -32,6 +34,13 @@ class WebLayerPermissionsClient : public permissions::PermissionsClient {
content::BrowserContext* browser_context,
ContentSettingsType type) override;
#if defined(OS_ANDROID)
+ bool IsPermissionControlledByDse(content::BrowserContext* browser_context,
+ ContentSettingsType type,
+ const url::Origin& origin) override;
+ bool ResetPermissionIfControlledByDse(
+ content::BrowserContext* browser_context,
+ ContentSettingsType type,
+ const url::Origin& origin) override;
void RepromptForAndroidPermissions(
content::WebContents* web_contents,
const std::vector<ContentSettingsType>& content_settings_types,
diff --git a/chromium/weblayer/browser/persistence/browser_persister.cc b/chromium/weblayer/browser/persistence/browser_persister.cc
index fac791261ab..61ea0b1ddb4 100644
--- a/chromium/weblayer/browser/persistence/browser_persister.cc
+++ b/chromium/weblayer/browser/persistence/browser_persister.cc
@@ -64,10 +64,10 @@ BrowserPersister::BrowserPersister(const base::FilePath& path,
rebuild_on_next_save_(false),
crypto_key_(decryption_key) {
browser_->AddObserver(this);
- command_storage_manager_->ScheduleGetCurrentSessionCommands(
+ command_storage_manager_->GetCurrentSessionCommands(
base::BindOnce(&BrowserPersister::OnGotCurrentSessionCommands,
- base::Unretained(this)),
- decryption_key, &cancelable_task_tracker_);
+ weak_factory_.GetWeakPtr()),
+ decryption_key);
}
BrowserPersister::~BrowserPersister() {
diff --git a/chromium/weblayer/browser/persistence/browser_persister.h b/chromium/weblayer/browser/persistence/browser_persister.h
index a956914ad59..d4578eeacf1 100644
--- a/chromium/weblayer/browser/persistence/browser_persister.h
+++ b/chromium/weblayer/browser/persistence/browser_persister.h
@@ -14,8 +14,8 @@
#include <vector>
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
-#include "base/task/cancelable_task_tracker.h"
#include "components/sessions/content/session_tab_helper_delegate.h"
#include "components/sessions/core/command_storage_manager_delegate.h"
#include "components/sessions/core/session_service_commands.h"
@@ -139,7 +139,7 @@ class BrowserPersister : public sessions::CommandStorageManagerDelegate,
&TabImpl::RemoveDataObserver>
data_observer_{this};
- base::CancelableTaskTracker cancelable_task_tracker_;
+ base::WeakPtrFactory<BrowserPersister> weak_factory_{this};
};
} // namespace weblayer
diff --git a/chromium/weblayer/browser/persistence/browser_persister_browsertest.cc b/chromium/weblayer/browser/persistence/browser_persister_browsertest.cc
index 23e30e3217c..a8eeec25f33 100644
--- a/chromium/weblayer/browser/persistence/browser_persister_browsertest.cc
+++ b/chromium/weblayer/browser/persistence/browser_persister_browsertest.cc
@@ -47,50 +47,6 @@ class BrowserPersisterTestHelper {
namespace {
using testing::UnorderedElementsAre;
-class OneShotNavigationObserver : public NavigationObserver {
- public:
- explicit OneShotNavigationObserver(Shell* shell) : tab_(shell->tab()) {
- tab_->GetNavigationController()->AddObserver(this);
- }
-
- ~OneShotNavigationObserver() override {
- tab_->GetNavigationController()->RemoveObserver(this);
- }
-
- void WaitForNavigation() { run_loop_.Run(); }
-
- bool completed() { return completed_; }
- bool is_error_page() { return is_error_page_; }
- Navigation::LoadError load_error() { return load_error_; }
- int http_status_code() { return http_status_code_; }
- NavigationState navigation_state() { return navigation_state_; }
-
- private:
- // NavigationObserver implementation:
- void NavigationCompleted(Navigation* navigation) override {
- completed_ = true;
- Finish(navigation);
- }
-
- void NavigationFailed(Navigation* navigation) override { Finish(navigation); }
-
- void Finish(Navigation* navigation) {
- is_error_page_ = navigation->IsErrorPage();
- load_error_ = navigation->GetLoadError();
- http_status_code_ = navigation->GetHttpStatusCode();
- navigation_state_ = navigation->GetState();
- run_loop_.Quit();
- }
-
- base::RunLoop run_loop_;
- Tab* tab_;
- bool completed_ = false;
- bool is_error_page_ = false;
- Navigation::LoadError load_error_ = Navigation::kNoError;
- int http_status_code_ = 0;
- NavigationState navigation_state_ = NavigationState::kWaitingResponse;
-};
-
class BrowserObserverImpl : public BrowserObserver {
public:
static void WaitForNewTab(Browser* browser) {
@@ -393,7 +349,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, MoveBetweenBrowsers) {
TabImpl* restored_tab_3 = static_cast<TabImpl*>(browser2->GetTabs()[0]);
EXPECT_TRUE(restored_tab_3->web_contents()->GetController().NeedsReload());
restored_tab_3->web_contents()->GetController().LoadIfNecessary();
- content::WaitForLoadStop(restored_tab_3->web_contents());
+ EXPECT_TRUE(content::WaitForLoadStop(restored_tab_3->web_contents()));
}
class BrowserPersisterTestWithTwoPersistedIds : public WebLayerBrowserTest {
diff --git a/chromium/weblayer/browser/persistence/browser_persister_file_utils.cc b/chromium/weblayer/browser/persistence/browser_persister_file_utils.cc
index ead41f214f9..8cec29c79e1 100644
--- a/chromium/weblayer/browser/persistence/browser_persister_file_utils.cc
+++ b/chromium/weblayer/browser/persistence/browser_persister_file_utils.cc
@@ -28,7 +28,7 @@ bool RemoveBrowserPersistenceStorageOnBackgroundThread(
for (const std::string& id : ids) {
DCHECK(!id.empty());
base::FilePath persistence_path = BuildPathForBrowserPersister(path, id);
- if (!base::DeleteFile(persistence_path, /* recurse */ false))
+ if (!base::DeleteFile(persistence_path))
all_succeeded = false;
}
return all_succeeded;
diff --git a/chromium/weblayer/browser/profile_browsertest.cc b/chromium/weblayer/browser/profile_browsertest.cc
index 3b8bbf3983b..9d11a603396 100644
--- a/chromium/weblayer/browser/profile_browsertest.cc
+++ b/chromium/weblayer/browser/profile_browsertest.cc
@@ -2,26 +2,191 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/test/bind_test_util.h"
#include "build/build_config.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "ui/gfx/image/image_unittest_util.h"
+#include "weblayer/browser/default_search_engine.h"
+#include "weblayer/browser/favicon/favicon_fetcher_impl.h"
+#include "weblayer/browser/favicon/test_favicon_fetcher_delegate.h"
+#include "weblayer/browser/host_content_settings_map_factory.h"
#include "weblayer/browser/profile_impl.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/shell/browser/shell.h"
#include "weblayer/test/weblayer_browser_test.h"
+#include "weblayer/test/weblayer_browser_test_utils.h"
namespace weblayer {
-using ProfileBrowsertest = WebLayerBrowserTest;
+using ProfileBrowserTest = WebLayerBrowserTest;
// TODO(crbug.com/654704): Android does not support PRE_ tests.
#if !defined(OS_ANDROID)
// UKM enabling via Profile persists across restarts.
-IN_PROC_BROWSER_TEST_F(ProfileBrowsertest, PRE_PersistUKM) {
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, PRE_PersistUKM) {
GetProfile()->SetBooleanSetting(SettingType::UKM_ENABLED, true);
}
-IN_PROC_BROWSER_TEST_F(ProfileBrowsertest, PersistUKM) {
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, PersistUKM) {
ASSERT_TRUE(GetProfile()->GetBooleanSetting(SettingType::UKM_ENABLED));
}
+// Enabling Network Prediction via Profile persists across restarts.
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, PRE_PersistNetworkPrediction) {
+ GetProfile()->SetBooleanSetting(SettingType::NETWORK_PREDICTION_ENABLED,
+ false);
+}
+
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, PersistNetworkPrediction) {
+ ASSERT_FALSE(
+ GetProfile()->GetBooleanSetting(SettingType::NETWORK_PREDICTION_ENABLED));
+}
+
#endif // !defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, GetCachedFaviconForPageUrl) {
+ // Navigation to a page with a favicon.
+ ASSERT_TRUE(embedded_test_server()->Start());
+ TestFaviconFetcherDelegate fetcher_delegate;
+ auto fetcher = shell()->tab()->CreateFaviconFetcher(&fetcher_delegate);
+ const GURL url =
+ embedded_test_server()->GetURL("/simple_page_with_favicon.html");
+ NavigateAndWaitForCompletion(url, shell());
+ fetcher_delegate.WaitForFavicon();
+ EXPECT_FALSE(fetcher_delegate.last_image().IsEmpty());
+ EXPECT_EQ(1, fetcher_delegate.on_favicon_changed_call_count());
+
+ // Request the favicon.
+ base::RunLoop run_loop;
+ static_cast<TabImpl*>(shell()->tab())
+ ->profile()
+ ->GetCachedFaviconForPageUrl(
+ url, base::BindLambdaForTesting([&](gfx::Image image) {
+ // The last parameter is the max difference allowed for each color
+ // component. As the image is encoded before saving to disk some
+ // variance is expected.
+ EXPECT_TRUE(gfx::test::AreImagesClose(
+ image, fetcher_delegate.last_image(), 10));
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, ClearBrowsingDataDeletesFavicons) {
+ // Navigate to a page with a favicon.
+ ASSERT_TRUE(embedded_test_server()->Start());
+ TestFaviconFetcherDelegate fetcher_delegate;
+ auto fetcher = shell()->tab()->CreateFaviconFetcher(&fetcher_delegate);
+ const GURL url =
+ embedded_test_server()->GetURL("/simple_page_with_favicon.html");
+ NavigateAndWaitForCompletion(url, shell());
+ fetcher_delegate.WaitForNonemptyFavicon();
+ EXPECT_FALSE(fetcher_delegate.last_image().IsEmpty());
+ EXPECT_EQ(1, fetcher_delegate.on_favicon_changed_call_count());
+
+ // Delete the favicons.
+ base::RunLoop run_loop;
+ base::Time now = base::Time::Now();
+ ProfileImpl* profile = static_cast<TabImpl*>(shell()->tab())->profile();
+ profile->ClearBrowsingData({BrowsingDataType::COOKIES_AND_SITE_DATA},
+ now - base::TimeDelta::FromMinutes(5), now,
+ run_loop.QuitClosure());
+ run_loop.Run();
+
+ // Ask for the cached favicon, there shouldn't be one.
+ base::RunLoop run_loop2;
+ profile->GetCachedFaviconForPageUrl(
+ url, base::BindLambdaForTesting([&](gfx::Image image) {
+ EXPECT_TRUE(image.IsEmpty());
+ run_loop2.Quit();
+ }));
+ run_loop2.Run();
+
+ // Navigate to another page, and verify favicon is downloaded.
+ fetcher_delegate.ClearLastImage();
+ const GURL url2 =
+ embedded_test_server()->GetURL("/simple_page_with_favicon2.html");
+ NavigateAndWaitForCompletion(url2, shell());
+ fetcher_delegate.WaitForNonemptyFavicon();
+ EXPECT_FALSE(fetcher_delegate.last_image().IsEmpty());
+ EXPECT_EQ(2, fetcher_delegate.on_favicon_changed_call_count());
+
+ // And fetch the favicon one more time.
+ base::RunLoop run_loop3;
+ profile->GetCachedFaviconForPageUrl(
+ url2, base::BindLambdaForTesting([&](gfx::Image image) {
+ EXPECT_FALSE(image.IsEmpty());
+ // The last parameter is the max difference allowed for each color
+ // component. As the image is encoded before saving to disk some
+ // variance is expected.
+ EXPECT_TRUE(gfx::test::AreImagesClose(
+ image, fetcher_delegate.last_image(), 10));
+ run_loop3.Quit();
+ }));
+ run_loop3.Run();
+}
+
+// Test default value.
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, DefaultNetworkPredictionState) {
+ ASSERT_TRUE(
+ GetProfile()->GetBooleanSetting(SettingType::NETWORK_PREDICTION_ENABLED));
+}
+
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, ClearSiteSettings) {
+ auto dse_origin = GetDseOrigin().GetURL();
+ auto foo_origin = GURL("http://www.foo.com");
+
+ auto* settings_map = HostContentSettingsMapFactory::GetForBrowserContext(
+ static_cast<TabImpl*>(shell()->tab())
+ ->web_contents()
+ ->GetBrowserContext());
+ EXPECT_EQ(settings_map->GetContentSetting(dse_origin, dse_origin,
+ ContentSettingsType::GEOLOCATION,
+ std::string()),
+ CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(settings_map->GetContentSetting(foo_origin, foo_origin,
+ ContentSettingsType::GEOLOCATION,
+ std::string()),
+ CONTENT_SETTING_ASK);
+
+ settings_map->SetContentSettingDefaultScope(
+ foo_origin, foo_origin, ContentSettingsType::GEOLOCATION, std::string(),
+ CONTENT_SETTING_ALLOW);
+
+ // Ensure clearing things other than site data doesn't change it
+ base::RunLoop run_loop;
+ base::Time now = base::Time::Now();
+ ProfileImpl* profile = static_cast<TabImpl*>(shell()->tab())->profile();
+ profile->ClearBrowsingData(
+ {BrowsingDataType::COOKIES_AND_SITE_DATA, BrowsingDataType::CACHE},
+ base::Time(), now, run_loop.QuitClosure());
+ run_loop.Run();
+
+ EXPECT_EQ(settings_map->GetContentSetting(dse_origin, dse_origin,
+ ContentSettingsType::GEOLOCATION,
+ std::string()),
+ CONTENT_SETTING_ALLOW);
+
+ EXPECT_EQ(settings_map->GetContentSetting(foo_origin, foo_origin,
+ ContentSettingsType::GEOLOCATION,
+ std::string()),
+ CONTENT_SETTING_ALLOW);
+
+ // Now clear site data.
+ base::RunLoop run_loop2;
+ profile->ClearBrowsingData({BrowsingDataType::SITE_SETTINGS}, base::Time(),
+ now, run_loop2.QuitClosure());
+ run_loop2.Run();
+
+ EXPECT_EQ(settings_map->GetContentSetting(dse_origin, dse_origin,
+ ContentSettingsType::GEOLOCATION,
+ std::string()),
+ CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(settings_map->GetContentSetting(foo_origin, foo_origin,
+ ContentSettingsType::GEOLOCATION,
+ std::string()),
+ CONTENT_SETTING_ASK);
+}
+
} // namespace weblayer
diff --git a/chromium/weblayer/browser/profile_disk_operations.cc b/chromium/weblayer/browser/profile_disk_operations.cc
index 736c102a8a3..874a3f30625 100644
--- a/chromium/weblayer/browser/profile_disk_operations.cc
+++ b/chromium/weblayer/browser/profile_disk_operations.cc
@@ -117,14 +117,14 @@ void MarkProfileAsDeleted(const ProfileInfo& info) {
void TryNukeProfileFromDisk(const ProfileInfo& info) {
if (info.name.empty()) {
// Incognito. Just delete session data.
- base::DeleteFileRecursively(ComputeBrowserPersisterDataBaseDir(info));
+ base::DeletePathRecursively(ComputeBrowserPersisterDataBaseDir(info));
return;
}
// This may fail, but that is ok since the marker is not deleted.
- base::DeleteFileRecursively(info.data_path);
+ base::DeletePathRecursively(info.data_path);
#if defined(OS_POSIX)
- base::DeleteFileRecursively(info.cache_path);
+ base::DeletePathRecursively(info.cache_path);
#endif
}
@@ -155,13 +155,13 @@ void NukeProfilesMarkedForDeletion() {
bool delete_success = true;
#if defined(OS_POSIX)
delete_success |=
- base::DeleteFileRecursively(GetCachePathFromDirName(dir_name));
+ base::DeletePathRecursively(GetCachePathFromDirName(dir_name));
#endif // OS_POSIX
delete_success |=
- base::DeleteFileRecursively(GetDataPathFromDirName(dir_name));
+ base::DeletePathRecursively(GetDataPathFromDirName(dir_name));
// Only delete the marker if deletion is successful.
if (delete_success) {
- base::DeleteFile(marker_path, /*recursive=*/false);
+ base::DeleteFile(marker_path);
}
}
}
diff --git a/chromium/weblayer/browser/profile_impl.cc b/chromium/weblayer/browser/profile_impl.cc
index 3cc8cc635af..5595d173216 100644
--- a/chromium/weblayer/browser/profile_impl.cc
+++ b/chromium/weblayer/browser/profile_impl.cc
@@ -18,6 +18,7 @@
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/prefs/pref_service.h"
#include "components/web_cache/browser/web_cache_manager.h"
#include "content/public/browser/browser_task_traits.h"
@@ -27,13 +28,18 @@
#include "content/public/browser/download_manager.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
#include "services/network/public/mojom/network_context.mojom.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
#include "weblayer/browser/android/metrics/weblayer_metrics_service_client.h"
#include "weblayer/browser/browser_context_impl.h"
#include "weblayer/browser/browser_impl.h"
#include "weblayer/browser/browser_list.h"
#include "weblayer/browser/browsing_data_remover_delegate.h"
#include "weblayer/browser/cookie_manager_impl.h"
+#include "weblayer/browser/favicon/favicon_service_impl.h"
+#include "weblayer/browser/favicon/favicon_service_impl_factory.h"
#include "weblayer/browser/persistence/browser_persister_file_utils.h"
#include "weblayer/browser/tab_impl.h"
@@ -44,6 +50,7 @@
#include "base/android/scoped_java_ref.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/unified_consent/pref_names.h"
+#include "ui/gfx/android/java_bitmap.h"
#include "weblayer/browser/browser_process.h"
#include "weblayer/browser/java/jni/ProfileImpl_jni.h"
#include "weblayer/browser/safe_browsing/safe_browsing_service.h"
@@ -111,6 +118,14 @@ void OnDidRemoveBrowserPersistenceStorage(
base::android::RunBooleanCallbackAndroid(callback, result);
}
+void OnDidGetCachedFaviconForPageUrl(
+ const base::android::ScopedJavaGlobalRef<jobject>& callback,
+ gfx::Image image) {
+ SkBitmap favicon = image.AsImageSkia().GetRepresentation(1.0f).GetBitmap();
+ base::android::RunObjectCallbackAndroid(
+ callback, favicon.empty() ? nullptr : gfx::ConvertToJavaBitmap(&favicon));
+}
+
#endif // OS_ANDROID
} // namespace
@@ -125,22 +140,30 @@ class ProfileImpl::DataClearer : public content::BrowsingDataRemover::Observer {
remover_->AddObserver(this);
}
- ~DataClearer() override { remover_->RemoveObserver(this); }
-
- void ClearData(uint64_t mask, base::Time from_time, base::Time to_time) {
+ void ClearData(ProfileImpl* profile,
+ uint64_t mask,
+ base::Time from_time,
+ base::Time to_time) {
uint64_t origin_types =
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB;
remover_->RemoveAndReply(from_time, to_time, mask, origin_types, this);
}
- void OnBrowsingDataRemoverDone() override {
+ // content::BrowsingDataRemover::Observer:
+ void OnBrowsingDataRemoverDone(uint64_t failed_data_types) override {
+ // Remove the observer now as after this returns the BrowserContext may
+ // be destroyed, which owns |remover_|.
+ remover_->RemoveObserver(this);
std::move(callback_).Run();
delete this;
}
private:
- content::BrowsingDataRemover* const remover_;
+ // DataClearer deletes itself when removal is done.
+ ~DataClearer() override = default;
+
+ content::BrowsingDataRemover* remover_;
base::OnceCallback<void()> callback_;
};
@@ -178,8 +201,16 @@ ProfileImpl::ProfileImpl(const std::string& name)
}
ProfileImpl::~ProfileImpl() {
- if (browser_context_)
+ // Destroy any scheduled WebContents. These implicitly refer to the
+ // BrowserContext and must be destroyed before the BrowserContext.
+ web_contents_to_delete_.clear();
+
+ if (browser_context_) {
+ BrowserContextDependencyManager::GetInstance()
+ ->DestroyBrowserContextServices(browser_context_.get());
browser_context_->ShutdownStoragePartitions();
+ }
+
GetProfiles().erase(this);
for (auto& observer : GetObservers())
observer.ProfileDestroyed(this);
@@ -202,6 +233,16 @@ void ProfileImpl::RemoveProfileObserver(ProfileObserver* observer) {
GetObservers().RemoveObserver(observer);
}
+void ProfileImpl::DeleteWebContentsSoon(
+ std::unique_ptr<content::WebContents> web_contents) {
+ if (web_contents_to_delete_.empty()) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&ProfileImpl::DeleteScheduleWebContents,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+ web_contents_to_delete_.push_back(std::move(web_contents));
+}
+
BrowserContextImpl* ProfileImpl::GetBrowserContext() {
if (browser_context_)
return browser_context_.get();
@@ -241,16 +282,22 @@ void ProfileImpl::ClearBrowsingData(
remove_mask |= content::BrowsingDataRemover::DATA_TYPE_DOM_STORAGE;
remove_mask |= content::BrowsingDataRemover::DATA_TYPE_MEDIA_LICENSES;
remove_mask |= BrowsingDataRemoverDelegate::DATA_TYPE_ISOLATED_ORIGINS;
+ remove_mask |= BrowsingDataRemoverDelegate::DATA_TYPE_FAVICONS;
+ remove_mask |= content::BrowsingDataRemover::DATA_TYPE_TRUST_TOKENS;
+ remove_mask |= content::BrowsingDataRemover::DATA_TYPE_CONVERSIONS;
break;
case BrowsingDataType::CACHE:
remove_mask |= content::BrowsingDataRemover::DATA_TYPE_CACHE;
ClearRendererCache();
break;
+ case BrowsingDataType::SITE_SETTINGS:
+ remove_mask |= BrowsingDataRemoverDelegate::DATA_TYPE_SITE_SETTINGS;
+ break;
default:
NOTREACHED();
}
}
- clearer->ClearData(remove_mask, from_time, to_time);
+ clearer->ClearData(this, remove_mask, from_time, to_time);
}
void ProfileImpl::SetDownloadDirectory(const base::FilePath& directory) {
@@ -367,14 +414,14 @@ void ProfileImpl::OnProfileMarked(std::unique_ptr<ProfileImpl> profile,
// Try to finish all writes and remove all data before nuking the profile.
profile->GetBrowserContext()->pref_service()->CommitPendingWrite();
- // Unretained is safe here because DataClearer is owned by
- // BrowserContextImpl which is owned by this.
+ ProfileImpl* raw_profile = profile.get();
auto* clearer = new DataClearer(
profile->GetBrowserContext(),
base::BindOnce(&ProfileImpl::NukeDataAfterRemovingData,
std::move(profile), std::move(done_callback)));
uint64_t remove_all_mask = 0xffffffffffffffffull;
- clearer->ClearData(remove_all_mask, base::Time::Min(), base::Time::Max());
+ clearer->ClearData(raw_profile, remove_all_mask, base::Time::Min(),
+ base::Time::Max());
}
#if defined(OS_ANDROID)
@@ -440,9 +487,8 @@ void ProfileImpl::ClearBrowsingData(
base::android::JavaIntArrayToIntVector(env, j_data_types, &data_type_ints);
std::vector<BrowsingDataType> data_types;
data_types.reserve(data_type_ints.size());
- for (int type : data_type_ints) {
+ for (int type : data_type_ints)
data_types.push_back(static_cast<BrowsingDataType>(type));
- }
ClearBrowsingData(
data_types,
base::Time::FromJavaTime(static_cast<int64_t>(j_from_time_millis)),
@@ -502,6 +548,16 @@ void ProfileImpl::PrepareForPossibleCrossOriginNavigation(JNIEnv* env) {
PrepareForPossibleCrossOriginNavigation();
}
+void ProfileImpl::GetCachedFaviconForPageUrl(
+ JNIEnv* env,
+ const base::android::JavaRef<jstring>& j_page_url,
+ const base::android::JavaRef<jobject>& j_callback) {
+ GetCachedFaviconForPageUrl(
+ GURL(base::android::ConvertJavaStringToUTF8(j_page_url)),
+ base::BindOnce(&OnDidGetCachedFaviconForPageUrl,
+ base::android::ScopedJavaGlobalRef<jobject>(j_callback)));
+}
+
#endif // OS_ANDROID
base::FilePath ProfileImpl::GetBrowserPersisterDataBaseDir() const {
@@ -513,8 +569,9 @@ void ProfileImpl::SetBooleanSetting(SettingType type, bool value) {
switch (type) {
case SettingType::BASIC_SAFE_BROWSING_ENABLED:
#if defined(OS_ANDROID)
- pref_service->SetBoolean(::prefs::kSafeBrowsingEnabled, value);
- pref_service->SetBoolean(::prefs::kSafeBrowsingEnhanced, false);
+ safe_browsing::SetSafeBrowsingState(
+ pref_service, value ? safe_browsing::STANDARD_PROTECTION
+ : safe_browsing::NO_SAFE_BROWSING);
#endif
break;
case SettingType::UKM_ENABLED: {
@@ -542,6 +599,8 @@ void ProfileImpl::SetBooleanSetting(SettingType type, bool value) {
value);
#endif
break;
+ case SettingType::NETWORK_PREDICTION_ENABLED:
+ pref_service->SetBoolean(prefs::kNoStatePrefetchEnabled, value);
}
}
@@ -567,10 +626,26 @@ bool ProfileImpl::GetBooleanSetting(SettingType type) {
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled);
#endif
return false;
+ case SettingType::NETWORK_PREDICTION_ENABLED:
+ return pref_service->GetBoolean(prefs::kNoStatePrefetchEnabled);
}
NOTREACHED();
}
+void ProfileImpl::GetCachedFaviconForPageUrl(
+ const GURL& page_url,
+ base::OnceCallback<void(gfx::Image)> callback) {
+ auto* service =
+ FaviconServiceImplFactory::GetForBrowserContext(GetBrowserContext());
+ if (!service) {
+ std::move(callback).Run({});
+ return;
+ }
+
+ service->GetFaviconForPageUrl(page_url, std::move(callback),
+ &cancelable_task_tracker_);
+}
+
void ProfileImpl::PrepareForPossibleCrossOriginNavigation() {
content::RenderProcessHost::WarmupSpareRenderProcessHost(GetBrowserContext());
}
@@ -581,4 +656,8 @@ int ProfileImpl::GetNumberOfBrowsers() {
[this](BrowserImpl* b) { return b->profile() == this; });
}
+void ProfileImpl::DeleteScheduleWebContents() {
+ web_contents_to_delete_.clear();
+}
+
} // namespace weblayer
diff --git a/chromium/weblayer/browser/profile_impl.h b/chromium/weblayer/browser/profile_impl.h
index d845d6bc646..5707d850ac9 100644
--- a/chromium/weblayer/browser/profile_impl.h
+++ b/chromium/weblayer/browser/profile_impl.h
@@ -6,10 +6,12 @@
#define WEBLAYER_BROWSER_PROFILE_IMPL_H_
#include <set>
+#include <vector>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/task/cancelable_task_tracker.h"
#include "build/build_config.h"
#include "weblayer/browser/i18n_util.h"
#include "weblayer/browser/profile_disk_operations.h"
@@ -22,6 +24,7 @@
namespace content {
class BrowserContext;
+class WebContents;
}
namespace weblayer {
@@ -63,6 +66,11 @@ class ProfileImpl : public Profile {
static void AddProfileObserver(ProfileObserver* observer);
static void RemoveProfileObserver(ProfileObserver* observer);
+ // Deletes |web_contents| after a delay. This is used if the owning Tab is
+ // deleted and it's not safe to delete the WebContents.
+ void DeleteWebContentsSoon(
+ std::unique_ptr<content::WebContents> web_contents);
+
BrowserContextImpl* GetBrowserContext();
// Called when the download subsystem has finished initializing. By this point
@@ -90,6 +98,9 @@ class ProfileImpl : public Profile {
base::flat_set<std::string> ids) override;
void SetBooleanSetting(SettingType type, bool value) override;
bool GetBooleanSetting(SettingType type) override;
+ void GetCachedFaviconForPageUrl(
+ const GURL& page_url,
+ base::OnceCallback<void(gfx::Image)> callback) override;
void PrepareForPossibleCrossOriginNavigation() override;
#if defined(OS_ANDROID)
@@ -123,6 +134,10 @@ class ProfileImpl : public Profile {
const base::android::JavaRef<jobjectArray>& j_ids,
const base::android::JavaRef<jobject>& j_callback);
void PrepareForPossibleCrossOriginNavigation(JNIEnv* env);
+ void GetCachedFaviconForPageUrl(
+ JNIEnv* env,
+ const base::android::JavaRef<jstring>& j_page_url,
+ const base::android::JavaRef<jobject>& j_callback);
#endif
const base::FilePath& download_directory() { return download_directory_; }
@@ -148,6 +163,8 @@ class ProfileImpl : public Profile {
// Returns the number of Browsers with this profile.
int GetNumberOfBrowsers();
+ void DeleteScheduleWebContents();
+
ProfileInfo info_;
std::unique_ptr<BrowserContextImpl> browser_context_;
@@ -164,6 +181,16 @@ class ProfileImpl : public Profile {
base::android::ScopedJavaGlobalRef<jobject> java_profile_;
#endif
+ // The typical pattern for CancelableTaskTrackers is to have the caller
+ // supply one. This code is predominantly called from the Java side, where
+ // CancelableTaskTracker isn't applicable. Because of this, the
+ // CancelableTaskTracker is owned by Profile.
+ base::CancelableTaskTracker cancelable_task_tracker_;
+
+ std::vector<std::unique_ptr<content::WebContents>> web_contents_to_delete_;
+
+ base::WeakPtrFactory<ProfileImpl> weak_ptr_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(ProfileImpl);
};
diff --git a/chromium/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.cc b/chromium/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.cc
index d3bee53a080..fe630ad4e39 100644
--- a/chromium/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.cc
+++ b/chromium/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.cc
@@ -13,7 +13,6 @@
#include "weblayer/browser/browser_process.h"
#include "weblayer/browser/feature_list_creator.h"
#include "weblayer/browser/safe_browsing/safe_browsing_service.h"
-#include "weblayer/browser/user_agent.h"
#include "weblayer/browser/verdict_cache_manager_factory.h"
namespace weblayer {
@@ -43,7 +42,7 @@ KeyedService* RealTimeUrlLookupServiceFactory::BuildServiceInstanceFor(
auto url_loader_factory =
std::make_unique<network::CrossThreadPendingSharedURLLoaderFactory>(
BrowserProcess::GetInstance()
- ->GetSafeBrowsingService(weblayer::GetUserAgent())
+ ->GetSafeBrowsingService()
->GetURLLoaderFactory());
return new safe_browsing::RealTimeUrlLookupService(
diff --git a/chromium/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc b/chromium/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc
index 77975384186..0af1ccd68e7 100644
--- a/chromium/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc
+++ b/chromium/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc
@@ -286,4 +286,4 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingDisabledBrowserTest,
safe_browsing::SB_THREAT_TYPE_URL_MALWARE, false);
}
-} // namespace weblayer \ No newline at end of file
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/safe_browsing/safe_browsing_service.cc b/chromium/weblayer/browser/safe_browsing/safe_browsing_service.cc
index fca167feed4..632d2f84d53 100644
--- a/chromium/weblayer/browser/safe_browsing/safe_browsing_service.cc
+++ b/chromium/weblayer/browser/safe_browsing/safe_browsing_service.cc
@@ -228,6 +228,12 @@ void SafeBrowsingService::StopDBManagerOnIOThread() {
}
}
+network::mojom::NetworkContext* SafeBrowsingService::GetNetworkContext() {
+ if (!network_context_)
+ return nullptr;
+ return network_context_->GetNetworkContext();
+}
+
scoped_refptr<network::SharedURLLoaderFactory>
SafeBrowsingService::GetURLLoaderFactory() {
if (!network_context_)
diff --git a/chromium/weblayer/browser/safe_browsing/safe_browsing_service.h b/chromium/weblayer/browser/safe_browsing/safe_browsing_service.h
index 1de5c0ff021..129a0ea1234 100644
--- a/chromium/weblayer/browser/safe_browsing/safe_browsing_service.h
+++ b/chromium/weblayer/browser/safe_browsing/safe_browsing_service.h
@@ -24,6 +24,9 @@ class URLLoaderThrottle;
}
namespace network {
+namespace mojom {
+class NetworkContext;
+}
class SharedURLLoaderFactory;
}
@@ -43,7 +46,7 @@ class UrlCheckerDelegateImpl;
// support for initialization and construction of these objects.
class SafeBrowsingService {
public:
- SafeBrowsingService(const std::string& user_agent);
+ explicit SafeBrowsingService(const std::string& user_agent);
~SafeBrowsingService();
// Executed on UI thread
@@ -57,6 +60,9 @@ class SafeBrowsingService {
void AddInterface(service_manager::BinderRegistry* registry,
content::RenderProcessHost* render_process_host);
void StopDBManager();
+
+ network::mojom::NetworkContext* GetNetworkContext();
+
scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory();
private:
diff --git a/chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.cc b/chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.cc
index a616dfef1b7..e55fde61de1 100644
--- a/chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.cc
+++ b/chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.cc
@@ -32,12 +32,12 @@ SafeBrowsingUIManager::SafeBrowsingUIManager(
SafeBrowsingUIManager::~SafeBrowsingUIManager() = default;
void SafeBrowsingUIManager::SendSerializedThreatDetails(
+ content::BrowserContext* browser_context,
const std::string& serialized) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!ping_manager_) {
ping_manager_ = ::safe_browsing::PingManager::Create(
- safe_browsing_service_->GetURLLoaderFactory(),
safe_browsing::GetV4ProtocolConfig(GetProtocolConfigClientName(),
false /* auto_update */));
}
@@ -46,7 +46,8 @@ void SafeBrowsingUIManager::SendSerializedThreatDetails(
return;
DVLOG(1) << "Sending serialized threat details";
- ping_manager_->ReportThreatDetails(serialized);
+ ping_manager_->ReportThreatDetails(
+ safe_browsing_service_->GetURLLoaderFactory(), serialized);
}
safe_browsing::BaseBlockingPage*
diff --git a/chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.h b/chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.h
index 989183c9c02..1fb00df3eb8 100644
--- a/chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.h
+++ b/chromium/weblayer/browser/safe_browsing/safe_browsing_ui_manager.h
@@ -29,7 +29,8 @@ class SafeBrowsingUIManager : public safe_browsing::BaseUIManager {
// Called on the UI thread by the ThreatDetails with the serialized
// protocol buffer, so the service can send it over.
- void SendSerializedThreatDetails(const std::string& serialized) override;
+ void SendSerializedThreatDetails(content::BrowserContext* browser_context,
+ const std::string& serialized) override;
protected:
~SafeBrowsingUIManager() override;
@@ -50,4 +51,4 @@ class SafeBrowsingUIManager : public safe_browsing::BaseUIManager {
} // namespace weblayer
-#endif // WEBLAYER_BROWSER_SAFE_BROWSING_SAFE_BROWSING_UI_MANAGER_H_ \ No newline at end of file
+#endif // WEBLAYER_BROWSER_SAFE_BROWSING_SAFE_BROWSING_UI_MANAGER_H_
diff --git a/chromium/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc b/chromium/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc
index 7ff46a3158c..3287dc72f45 100644
--- a/chromium/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc
+++ b/chromium/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc
@@ -5,14 +5,31 @@
#include "weblayer/browser/safe_browsing/url_checker_delegate_impl.h"
#include "base/bind.h"
+#include "components/prerender/browser/prerender_manager.h"
#include "components/safe_browsing/core/db/database_manager.h"
#include "components/security_interstitials/core/unsafe_resource.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
+#include "weblayer/browser/no_state_prefetch/prerender_utils.h"
#include "weblayer/browser/safe_browsing/safe_browsing_ui_manager.h"
namespace weblayer {
+namespace {
+
+// Destroys the prerender contents associated with the web_contents, if any.
+void DestroyPrerenderContents(
+ content::WebContents::OnceGetter web_contents_getter) {
+ content::WebContents* web_contents = std::move(web_contents_getter).Run();
+
+ auto* prerender_contents = PrerenderContentsFromWebContents(web_contents);
+ if (prerender_contents)
+ prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
+}
+
+} // namespace
+
UrlCheckerDelegateImpl::UrlCheckerDelegateImpl(
scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager,
scoped_refptr<SafeBrowsingUIManager> ui_manager)
@@ -27,7 +44,12 @@ UrlCheckerDelegateImpl::UrlCheckerDelegateImpl(
UrlCheckerDelegateImpl::~UrlCheckerDelegateImpl() = default;
void UrlCheckerDelegateImpl::MaybeDestroyPrerenderContents(
- content::WebContents::OnceGetter web_contents_getter) {}
+ content::WebContents::OnceGetter web_contents_getter) {
+ // Destroy the prefetch with FINAL_STATUS_SAFEBROSWING.
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(&DestroyPrerenderContents,
+ std::move(web_contents_getter)));
+}
void UrlCheckerDelegateImpl::StartDisplayingBlockingPageHelper(
const security_interstitials::UnsafeResource& resource,
diff --git a/chromium/weblayer/browser/signin_url_loader_throttle.cc b/chromium/weblayer/browser/signin_url_loader_throttle.cc
new file mode 100644
index 00000000000..7758529a650
--- /dev/null
+++ b/chromium/weblayer/browser/signin_url_loader_throttle.cc
@@ -0,0 +1,192 @@
+// Copyright 2020 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 "weblayer/browser/signin_url_loader_throttle.h"
+
+#include "base/task/post_task.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/signin/core/browser/signin_header_helper.h"
+#include "components/signin/public/base/account_consistency_method.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "google_apis/gaia/gaia_auth_util.h"
+#include "net/base/url_util.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
+#include "weblayer/browser/cookie_settings_factory.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/public/google_accounts_delegate.h"
+
+namespace weblayer {
+
+const char kSignOutPath[] = "/SignOutOptions";
+
+namespace {
+constexpr char kWebLayerMirrorHeaderSource[] = "WebLayer";
+
+GoogleAccountsDelegate* GetDelegate(
+ const content::WebContents::Getter& web_contents_getter) {
+ auto* web_contents = web_contents_getter.Run();
+ if (!web_contents)
+ return nullptr;
+
+ auto* tab = TabImpl::FromWebContents(web_contents);
+ if (!tab)
+ return nullptr;
+
+ return tab->google_accounts_delegate();
+}
+
+void ProcessMirrorHeader(content::WebContents::Getter web_contents_getter,
+ const signin::ManageAccountsParams& params) {
+ auto* delegate = GetDelegate(web_contents_getter);
+ if (delegate)
+ delegate->OnGoogleAccountsRequest(params);
+}
+
+void MaybeAddQueryParams(GURL* url) {
+ // Add manage=true to query parameters for sign out URLs to make sure we
+ // receive the Mirror response headers instead of the normal sign out page.
+ if (gaia::IsGaiaSignonRealm(url->GetOrigin()) &&
+ url->path_piece() == kSignOutPath) {
+ *url = net::AppendOrReplaceQueryParameter(*url, "manage", "true");
+ }
+}
+} // namespace
+
+SigninURLLoaderThrottle::~SigninURLLoaderThrottle() = default;
+
+// static
+std::unique_ptr<SigninURLLoaderThrottle> SigninURLLoaderThrottle::Create(
+ content::BrowserContext* browser_context,
+ content::WebContents::Getter web_contents_getter) {
+ if (browser_context->IsOffTheRecord() || !GetDelegate(web_contents_getter))
+ return nullptr;
+
+ // Use base::WrapUnique + new because of the constructor is private.
+ return base::WrapUnique(new SigninURLLoaderThrottle(
+ browser_context, std::move(web_contents_getter)));
+}
+
+void SigninURLLoaderThrottle::WillStartRequest(
+ network::ResourceRequest* request,
+ bool* defer) {
+ GoogleAccountsDelegate* delegate = GetDelegate(web_contents_getter_);
+ if (!delegate)
+ return;
+
+ MaybeAddQueryParams(&request->url);
+
+ request_url_ = request->url;
+ is_main_frame_ =
+ static_cast<blink::mojom::ResourceType>(request->resource_type) ==
+ blink::mojom::ResourceType::kMainFrame;
+
+ net::HttpRequestHeaders modified_request_headers;
+ std::vector<std::string> to_be_removed_request_headers;
+ ProcessRequest(GURL(), &request->headers, &to_be_removed_request_headers,
+ &modified_request_headers);
+ signin::RequestAdapter adapter(request_url_, request->headers,
+ &modified_request_headers,
+ &to_be_removed_request_headers);
+ request_headers_.CopyFrom(request->headers);
+}
+
+void SigninURLLoaderThrottle::WillRedirectRequest(
+ net::RedirectInfo* redirect_info,
+ const network::mojom::URLResponseHead& response_head,
+ bool* defer,
+ std::vector<std::string>* headers_to_remove,
+ net::HttpRequestHeaders* modified_headers,
+ net::HttpRequestHeaders* modified_cors_exempt_request_headers) {
+ if (!GetDelegate(web_contents_getter_))
+ return;
+
+ MaybeAddQueryParams(&redirect_info->new_url);
+
+ ProcessRequest(redirect_info->new_url, &request_headers_, headers_to_remove,
+ modified_headers);
+ ProcessResponse(response_head.headers.get());
+
+ request_url_ = redirect_info->new_url;
+}
+
+void SigninURLLoaderThrottle::WillProcessResponse(
+ const GURL& response_url,
+ network::mojom::URLResponseHead* response_head,
+ bool* defer) {
+ if (!GetDelegate(web_contents_getter_))
+ return;
+
+ ProcessResponse(response_head->headers.get());
+}
+
+SigninURLLoaderThrottle::SigninURLLoaderThrottle(
+ content::BrowserContext* browser_context,
+ content::WebContents::Getter web_contents_getter)
+ : browser_context_(browser_context),
+ web_contents_getter_(std::move(web_contents_getter)) {}
+
+void SigninURLLoaderThrottle::ProcessRequest(
+ const GURL& new_url,
+ net::HttpRequestHeaders* original_headers,
+ std::vector<std::string>* headers_to_remove,
+ net::HttpRequestHeaders* modified_headers) {
+ GoogleAccountsDelegate* delegate = GetDelegate(web_contents_getter_);
+ if (!delegate)
+ return;
+
+ signin::RequestAdapter request_adapter(request_url_, *original_headers,
+ modified_headers, headers_to_remove);
+ // Disable incognito and adding accounts for now. This shouldn't matter in
+ // practice though since we are skipping the /SignOutOptions page completely
+ // with the manage=true param.
+ signin::AppendOrRemoveMirrorRequestHeader(
+ &request_adapter, new_url, delegate->GetGaiaId(),
+ signin::AccountConsistencyMethod::kMirror,
+ CookieSettingsFactory::GetForBrowserContext(browser_context_).get(),
+ signin::PROFILE_MODE_INCOGNITO_DISABLED |
+ signin::PROFILE_MODE_ADD_ACCOUNT_DISABLED,
+ kWebLayerMirrorHeaderSource, true /* force_account_consistency */);
+
+ original_headers->MergeFrom(*modified_headers);
+ for (const std::string& name : *headers_to_remove)
+ original_headers->RemoveHeader(name);
+}
+
+void SigninURLLoaderThrottle::ProcessResponse(
+ const net::HttpResponseHeaders* headers) {
+ if (!gaia::IsGaiaSignonRealm(request_url_.GetOrigin()) || !is_main_frame_ ||
+ !headers) {
+ return;
+ }
+
+ std::string header_value;
+ if (!headers->GetNormalizedHeader(signin::kChromeManageAccountsHeader,
+ &header_value)) {
+ return;
+ }
+
+ signin::ManageAccountsParams params =
+ signin::BuildManageAccountsParams(header_value);
+ if (params.service_type == signin::GAIA_SERVICE_TYPE_NONE)
+ return;
+
+ // Only process one mirror header per request (multiple headers on the same
+ // redirect chain are ignored).
+ if (response_header_processed_) {
+ LOG(ERROR) << "Multiple X-Chrome-Manage-Accounts headers on a redirect "
+ << "chain, ignoring";
+ return;
+ }
+
+ response_header_processed_ = true;
+
+ // Post a task even if we are already on the UI thread to avoid making any
+ // requests while processing a throttle event.
+ base::PostTask(
+ FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(&ProcessMirrorHeader, web_contents_getter_, params));
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/signin_url_loader_throttle.h b/chromium/weblayer/browser/signin_url_loader_throttle.h
new file mode 100644
index 00000000000..118e46e9751
--- /dev/null
+++ b/chromium/weblayer/browser/signin_url_loader_throttle.h
@@ -0,0 +1,61 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_SIGNIN_URL_LOADER_THROTTLE_H_
+#define WEBLAYER_BROWSER_SIGNIN_URL_LOADER_THROTTLE_H_
+
+#include "components/signin/core/browser/signin_header_helper.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
+#include "net/http/http_request_headers.h"
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
+
+namespace weblayer {
+
+// Exposed for testing.
+extern const char kSignOutPath[];
+
+class SigninURLLoaderThrottle : public blink::URLLoaderThrottle {
+ public:
+ ~SigninURLLoaderThrottle() override;
+
+ static std::unique_ptr<SigninURLLoaderThrottle> Create(
+ content::BrowserContext* browser_context,
+ content::WebContents::Getter web_contents_getter);
+
+ // blink::URLLoaderThrottle
+ void WillStartRequest(network::ResourceRequest* request,
+ bool* defer) override;
+ void WillRedirectRequest(
+ net::RedirectInfo* redirect_info,
+ const network::mojom::URLResponseHead& response_head,
+ bool* defer,
+ std::vector<std::string>* headers_to_remove,
+ net::HttpRequestHeaders* modified_headers,
+ net::HttpRequestHeaders* modified_cors_exempt_request_headers) override;
+ void WillProcessResponse(const GURL& response_url,
+ network::mojom::URLResponseHead* response_head,
+ bool* defer) override;
+
+ private:
+ SigninURLLoaderThrottle(content::BrowserContext* browser_context,
+ content::WebContents::Getter web_contents_getter);
+
+ void ProcessRequest(const GURL& url,
+ net::HttpRequestHeaders* original_headers,
+ std::vector<std::string>* headers_to_remove,
+ net::HttpRequestHeaders* modified_headers);
+ void ProcessResponse(const net::HttpResponseHeaders* headers);
+
+ content::BrowserContext* browser_context_;
+ content::WebContents::Getter web_contents_getter_;
+ net::HttpRequestHeaders request_headers_;
+ GURL request_url_;
+ bool is_main_frame_ = false;
+ bool response_header_processed_ = false;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_SIGNIN_URL_LOADER_THROTTLE_H_
diff --git a/chromium/weblayer/browser/ssl_browsertest.cc b/chromium/weblayer/browser/ssl_browsertest.cc
index 0ef9fa45322..4006e99088d 100644
--- a/chromium/weblayer/browser/ssl_browsertest.cc
+++ b/chromium/weblayer/browser/ssl_browsertest.cc
@@ -8,14 +8,22 @@
#include "base/macros.h"
#include "base/optional.h"
#include "base/scoped_observer.h"
+#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "components/network_time/network_time_tracker.h"
+#include "components/security_interstitials/content/insecure_form_blocking_page.h"
+#include "components/security_interstitials/content/ssl_error_assistant.h"
#include "components/security_interstitials/content/ssl_error_handler.h"
+#include "components/security_interstitials/core/features.h"
+#include "net/ssl/ssl_info.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "weblayer/browser/browser_process.h"
#include "weblayer/browser/weblayer_security_blocking_page_factory.h"
#include "weblayer/public/browser.h"
#include "weblayer/public/browser_observer.h"
+#include "weblayer/public/error_page.h"
+#include "weblayer/public/error_page_delegate.h"
+#include "weblayer/public/tab.h"
#include "weblayer/shell/browser/shell.h"
#include "weblayer/test/interstitial_utils.h"
#include "weblayer/test/load_completion_observer.h"
@@ -53,6 +61,24 @@ class NewTabWaiter : public BrowserObserver {
};
#endif
+class TestErrorPageDelegate : public ErrorPageDelegate {
+ public:
+ bool was_get_error_page_content_called() const {
+ return was_get_error_page_content_called_;
+ }
+
+ // ErrorPageDelegate:
+ bool OnBackToSafety() override { return false; }
+ std::unique_ptr<ErrorPage> GetErrorPageContent(
+ Navigation* navigation) override {
+ was_get_error_page_content_called_ = true;
+ return std::make_unique<ErrorPage>();
+ }
+
+ private:
+ bool was_get_error_page_content_called_ = false;
+};
+
} // namespace
class SSLBrowserTest : public WebLayerBrowserTest {
@@ -355,4 +381,95 @@ IN_PROC_BROWSER_TEST_F(SSLBrowserTest, BadClockInterstitial) {
NavigateToPageWithExpiredCertExpectBadClockInterstitial();
}
+// This test verifies that a certificate in the list of known captive portal
+// certificates in ssl_error_assistant.asciipb is detected as such. This serves
+// to verify that the ssl_error_assistant proto was correctly loaded.
+IN_PROC_BROWSER_TEST_F(SSLBrowserTest,
+ CertificateInKnownCaptivePortalsListDetected) {
+ net::SSLInfo ssl_info_with_known_captive_portal_cert;
+ net::HashValue captive_portal_public_key;
+
+ // Set up the SSSLInfo with the certificate of captive-portal.badssl.com
+ // (taken from ssl_error_assistant.asciipb).
+ ASSERT_TRUE(captive_portal_public_key.FromString(
+ "sha256/fjZPHewEHTrMDX3I1ecEIeoy3WFxHyGplOLv28kIbtI="));
+ net::HashValueVector public_keys;
+ public_keys.push_back(captive_portal_public_key);
+ ssl_info_with_known_captive_portal_cert.public_key_hashes = public_keys;
+
+ EXPECT_TRUE(SSLErrorAssistant().IsKnownCaptivePortalCertificate(
+ ssl_info_with_known_captive_portal_cert));
+}
+
+// Verifies an error page is not requested for an ssl error.
+IN_PROC_BROWSER_TEST_F(SSLBrowserTest, ErrorPageNotCalledForMismatch) {
+ TestErrorPageDelegate error_page_delegate;
+ shell()->tab()->SetErrorPageDelegate(&error_page_delegate);
+ NavigateToOkPage();
+ EXPECT_FALSE(error_page_delegate.was_get_error_page_content_called());
+ NavigateToPageWithMismatchedCertExpectSSLInterstitial();
+ EXPECT_FALSE(error_page_delegate.was_get_error_page_content_called());
+}
+
+class SSLBrowserTestWithInsecureFormsWarningEnabled : public SSLBrowserTest {
+ public:
+ SSLBrowserTestWithInsecureFormsWarningEnabled() {
+ feature_list_.InitAndEnableFeature(
+ security_interstitials::kInsecureFormSubmissionInterstitial);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+// Visits a page that displays an insecure form, submits the form, and checks an
+// interstitial is shown.
+IN_PROC_BROWSER_TEST_F(SSLBrowserTestWithInsecureFormsWarningEnabled,
+ TestDisplaysInsecureFormSubmissionWarning) {
+ GURL insecure_form_url = https_server_->GetURL("/insecure_form.html");
+ GURL form_target_url = GURL("http://does-not-exist.test/form_target.html?");
+ NavigateAndWaitForCompletion(insecure_form_url, shell());
+
+ // Submit the form and wait for the interstitial to load.
+ TestNavigationObserver navigation_observer(
+ form_target_url, TestNavigationObserver::NavigationEvent::kFailure,
+ shell());
+ ExecuteScript(shell(), "submitForm();", false /*use_separate_isolate*/);
+ navigation_observer.Wait();
+
+ // Check the correct interstitial loaded.
+ EXPECT_TRUE(IsShowingInsecureFormInterstitial(shell()->tab()));
+}
+
+class SSLBrowserTestWithInsecureFormsWarningDisabled : public SSLBrowserTest {
+ public:
+ SSLBrowserTestWithInsecureFormsWarningDisabled() {
+ feature_list_.InitAndDisableFeature(
+ security_interstitials::kInsecureFormSubmissionInterstitial);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+// Visits a page that displays an insecure form, submits the form, and checks no
+// interstitial is displayed with the feature off.
+IN_PROC_BROWSER_TEST_F(SSLBrowserTestWithInsecureFormsWarningDisabled,
+ TestNoInsecureFormWarning) {
+ GURL insecure_form_url = https_server_->GetURL("/insecure_form.html");
+ GURL form_target_url = GURL("http://does-not-exist.test/form_target.html?");
+ NavigateAndWaitForCompletion(insecure_form_url, shell());
+
+ // Submit the form and wait for the form target to load. We wait for a
+ // failure since the target url is not served.
+ TestNavigationObserver navigation_observer(
+ form_target_url, TestNavigationObserver::NavigationEvent::kFailure,
+ shell());
+ ExecuteScript(shell(), "submitForm();", false /*use_separate_isolate*/);
+ navigation_observer.Wait();
+
+ // Check no interstitial loaded.
+ EXPECT_FALSE(IsShowingSecurityInterstitial(shell()->tab()));
+}
+
} // namespace weblayer
diff --git a/chromium/weblayer/browser/system_network_context_manager.h b/chromium/weblayer/browser/system_network_context_manager.h
index 2bb7c434920..446553298c4 100644
--- a/chromium/weblayer/browser/system_network_context_manager.h
+++ b/chromium/weblayer/browser/system_network_context_manager.h
@@ -52,6 +52,10 @@ class SystemNetworkContextManager {
// Returns a SharedURLLoaderFactory owned by the SystemNetworkContextManager
// that is backed by the SystemNetworkContext.
+ // NOTE: This factory assumes that the network service is running in the
+ // browser process, which is a valid assumption for Android. If WebLayer is
+ // productionized beyond Android, it will need to be extended to handle
+ // network service crashes.
scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory();
private:
diff --git a/chromium/weblayer/browser/tab_impl.cc b/chromium/weblayer/browser/tab_impl.cc
index 052dbcb9517..cc4bb136cd8 100644
--- a/chromium/weblayer/browser/tab_impl.cc
+++ b/chromium/weblayer/browser/tab_impl.cc
@@ -21,8 +21,7 @@
#include "components/blocked_content/popup_opener_tab_helper.h"
#include "components/blocked_content/popup_tracker.h"
#include "components/captive_portal/core/buildflags.h"
-#include "components/client_hints/browser/client_hints.h"
-#include "components/content_settings/browser/tab_specific_content_settings.h"
+#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/find_in_page/find_tab_helper.h"
#include "components/find_in_page/find_types.h"
#include "components/js_injection/browser/js_communication_host.h"
@@ -55,19 +54,22 @@
#include "weblayer/browser/browser_impl.h"
#include "weblayer/browser/browser_process.h"
#include "weblayer/browser/content_browser_client_impl.h"
+#include "weblayer/browser/favicon/favicon_fetcher_impl.h"
+#include "weblayer/browser/favicon/favicon_tab_helper.h"
#include "weblayer/browser/file_select_helper.h"
#include "weblayer/browser/host_content_settings_map_factory.h"
#include "weblayer/browser/i18n_util.h"
#include "weblayer/browser/infobar_service.h"
#include "weblayer/browser/js_communication/web_message_host_factory_wrapper.h"
#include "weblayer/browser/navigation_controller_impl.h"
+#include "weblayer/browser/no_state_prefetch/prerender_tab_helper.h"
#include "weblayer/browser/page_load_metrics_initialize.h"
+#include "weblayer/browser/page_specific_content_settings_delegate.h"
#include "weblayer/browser/password_manager_driver_factory.h"
#include "weblayer/browser/permissions/permission_manager_factory.h"
#include "weblayer/browser/persistence/browser_persister.h"
#include "weblayer/browser/popup_navigation_delegate_impl.h"
#include "weblayer/browser/profile_impl.h"
-#include "weblayer/browser/tab_specific_content_settings_delegate.h"
#include "weblayer/browser/translate_client_impl.h"
#include "weblayer/browser/weblayer_features.h"
#include "weblayer/common/isolated_world_ids.h"
@@ -88,9 +90,11 @@
#include "base/json/json_writer.h"
#include "base/trace_event/trace_event.h"
#include "components/autofill/android/provider/autofill_provider_android.h"
+#include "components/browser_ui/sms/android/sms_infobar.h"
#include "components/embedder_support/android/contextmenu/context_menu_builder.h"
#include "components/embedder_support/android/delegate/color_chooser_android.h"
#include "components/javascript_dialogs/tab_modal_dialog_manager.h" // nogncheck
+#include "components/translate/core/browser/translate_manager.h"
#include "ui/android/view_android.h"
#include "ui/gfx/android/java_bitmap.h"
#include "weblayer/browser/browser_controls_container_view.h"
@@ -100,6 +104,7 @@
#include "weblayer/browser/java/jni/TabImpl_jni.h"
#include "weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.h"
#include "weblayer/browser/js_communication/web_message_host_factory_proxy.h"
+#include "weblayer/browser/translate_client_impl.h"
#include "weblayer/browser/weblayer_factory_impl_android.h"
#include "weblayer/browser/webrtc/media_stream_manager.h"
#endif
@@ -242,8 +247,10 @@ static ScopedJavaLocalRef<jobject> JNI_TabImpl_FromWebContents(
return nullptr;
}
-TabImpl::TabImpl(ProfileImpl* profile, const JavaParamRef<jobject>& java_impl)
- : TabImpl(profile) {
+TabImpl::TabImpl(ProfileImpl* profile,
+ const JavaParamRef<jobject>& java_impl,
+ std::unique_ptr<content::WebContents> web_contents)
+ : TabImpl(profile, std::move(web_contents)) {
java_impl_ = java_impl;
}
#endif
@@ -255,16 +262,15 @@ TabImpl::TabImpl(ProfileImpl* profile,
web_contents_(std::move(web_contents)),
guid_(guid.empty() ? base::GenerateGUID() : guid) {
GetTabs().insert(this);
- if (web_contents_) {
- // This code path is hit when the page requests a new tab, which should
- // only be possible from the same profile.
- DCHECK_EQ(profile_->GetBrowserContext(),
- web_contents_->GetBrowserContext());
- } else {
- content::WebContents::CreateParams create_params(
- profile_->GetBrowserContext());
- web_contents_ = content::WebContents::Create(create_params);
- }
+ DCHECK(web_contents_);
+ // This code path is hit when the page requests a new tab, which should
+ // only be possible from the same profile.
+ DCHECK_EQ(profile_->GetBrowserContext(), web_contents_->GetBrowserContext());
+
+ // FaviconTabHelper adds a WebContentsObserver. Create FaviconTabHelper
+ // before |this| observes the WebContents to ensure favicons are reset before
+ // notifying weblayer observers of changes.
+ FaviconTabHelper::CreateForWebContents(web_contents_.get());
// By default renderer initiated navigations inherit the user-agent override
// of the current NavigationEntry. For WebLayer, the user-agent override is
@@ -297,21 +303,14 @@ TabImpl::TabImpl(ProfileImpl* profile,
sessions::SessionTabHelper::CreateForWebContents(
web_contents_.get(),
- base::BindRepeating(&TabImpl::GetSessionServiceTabHelperDelegate,
- base::Unretained(this)));
+ base::BindRepeating(&TabImpl::GetSessionServiceTabHelperDelegate));
permissions::PermissionRequestManager::CreateForWebContents(
web_contents_.get());
- PrefService* local_state = BrowserProcess::GetInstance()->GetLocalState();
- client_hints::ClientHints::CreateForWebContents(
+ content_settings::PageSpecificContentSettings::CreateForWebContents(
web_contents_.get(),
- BrowserProcess::GetInstance()->GetNetworkQualityTracker(),
- HostContentSettingsMapFactory::GetForBrowserContext(
- web_contents_->GetBrowserContext()),
- GetUserAgentMetadata(), local_state);
- content_settings::TabSpecificContentSettings::CreateForWebContents(
- web_contents_.get(), std::make_unique<TabSpecificContentSettingsDelegate>(
- web_contents_.get()));
+ std::make_unique<PageSpecificContentSettingsDelegate>(
+ web_contents_.get()));
blocked_content::PopupBlockerTabHelper::CreateForWebContents(
web_contents_.get());
blocked_content::PopupOpenerTabHelper::CreateForWebContents(
@@ -343,6 +342,9 @@ TabImpl::TabImpl(ProfileImpl* profile,
base::BindRepeating(&OpenCaptivePortalLoginTabInWebContents,
web_contents_.get()));
#endif
+
+ // PrerenderTabHelper adds a WebContentsObserver.
+ PrerenderTabHelper::CreateForWebContents(web_contents_.get());
}
TabImpl::~TabImpl() {
@@ -360,6 +362,18 @@ TabImpl::~TabImpl() {
#endif
Observe(nullptr);
web_contents_->SetDelegate(nullptr);
+ if (navigation_controller_->should_delay_web_contents_deletion()) {
+ // Some user-data on WebContents directly or indirectly references this.
+ // Remove that linkage to avoid use-after-free.
+ web_contents_->RemoveUserData(&kWebContentsUserDataKey);
+ web_contents_->RemoveUserData(
+ autofill::ContentAutofillDriverFactory::
+ kContentAutofillDriverFactoryWebContentsUserDataKey);
+ // Have Profile handle the task posting to ensure the WebContents is
+ // deleted before Profile. To do otherwise means it would be possible for
+ // the Profile to outlive the WebContents, which is problematic (crash).
+ profile_->DeleteWebContentsSoon(std::move(web_contents_));
+ }
web_contents_.reset();
GetTabs().erase(this);
}
@@ -407,15 +421,18 @@ void TabImpl::SetFullscreenDelegate(FullscreenDelegate* delegate) {
// Whether fullscreen is enabled depends upon whether there is a delegate. If
// having a delegate changed, then update the renderer (which is where
// fullscreen enabled is tracked).
- content::RenderViewHost* host = web_contents_->GetRenderViewHost();
- if (had_delegate != has_delegate && host)
- host->OnWebkitPreferencesChanged();
+ if (had_delegate != has_delegate)
+ web_contents_->OnWebPreferencesChanged();
}
void TabImpl::SetNewTabDelegate(NewTabDelegate* delegate) {
new_tab_delegate_ = delegate;
}
+void TabImpl::SetGoogleAccountsDelegate(GoogleAccountsDelegate* delegate) {
+ google_accounts_delegate_ = delegate;
+}
+
void TabImpl::AddObserver(TabObserver* observer) {
observers_.AddObserver(observer);
}
@@ -480,6 +497,11 @@ void TabImpl::ExecuteScriptWithUserGestureForTests(
script);
}
+std::unique_ptr<FaviconFetcher> TabImpl::CreateFaviconFetcher(
+ FaviconFetcherDelegate* delegate) {
+ return std::make_unique<FaviconFetcherImpl>(web_contents_.get(), delegate);
+}
+
#if !defined(OS_ANDROID)
void TabImpl::AttachToView(views::WebView* web_view) {
web_view->SetWebContents(web_contents_.get());
@@ -488,7 +510,7 @@ void TabImpl::AttachToView(views::WebView* web_view) {
#endif
void TabImpl::WebPreferencesChanged() {
- web_contents_->GetRenderViewHost()->OnWebkitPreferencesChanged();
+ web_contents_->OnWebPreferencesChanged();
}
void TabImpl::SetWebPreferences(content::WebPreferences* prefs) {
@@ -547,15 +569,20 @@ void TabImpl::DisableAutofillSystemIntegrationForTesting() {
static jlong JNI_TabImpl_CreateTab(JNIEnv* env,
jlong profile,
const JavaParamRef<jobject>& java_impl) {
- return reinterpret_cast<intptr_t>(
- new TabImpl(reinterpret_cast<ProfileImpl*>(profile), java_impl));
+ ProfileImpl* profile_impl = reinterpret_cast<ProfileImpl*>(profile);
+ content::WebContents::CreateParams create_params(
+ profile_impl->GetBrowserContext());
+ create_params.initially_hidden = true;
+ return reinterpret_cast<intptr_t>(new TabImpl(
+ profile_impl, java_impl, content::WebContents::Create(create_params)));
}
static void JNI_TabImpl_DeleteTab(JNIEnv* env, jlong tab) {
TabImpl* tab_impl = reinterpret_cast<TabImpl*>(tab);
DCHECK(tab_impl);
DCHECK(tab_impl->browser());
- tab_impl->browser()->DestroyTab(tab_impl);
+ // Don't call Browser::DestroyTab() as it calls back to the java side.
+ tab_impl->browser()->DestroyTabFromJava(tab_impl);
}
ScopedJavaLocalRef<jobject> TabImpl::GetWebContents(JNIEnv* env) {
@@ -615,12 +642,15 @@ void TabImpl::OnAutofillProviderChanged(
provider->OnJavaAutofillProviderChanged(env, autofill_provider);
}
-void TabImpl::UpdateBrowserControlsState(JNIEnv* env,
- jint raw_new_state,
- jboolean animate) {
- UpdateBrowserControlsStateImpl(
- static_cast<content::BrowserControlsState>(raw_new_state),
- current_browser_controls_state_, animate);
+void TabImpl::UpdateBrowserControlsConstraint(JNIEnv* env,
+ jint constraint,
+ jboolean animate) {
+ current_browser_controls_visibility_constraint_ =
+ static_cast<content::BrowserControlsState>(constraint);
+ // Passing BOTH here means that it doesn't matter what state the controls are
+ // currently in; don't change the current state unless it's incompatible with
+ // the new constraint.
+ UpdateBrowserControlsState(content::BROWSER_CONTROLS_STATE_BOTH, animate);
}
ScopedJavaLocalRef<jstring> TabImpl::GetGuid(JNIEnv* env) {
@@ -671,15 +701,15 @@ TabImpl::ScreenShotErrors TabImpl::PrepareForCaptureScreenShot(
return ScreenShotErrors::kNone;
}
-void TabImpl::UpdateBrowserControlsStateImpl(
+void TabImpl::UpdateBrowserControlsState(
content::BrowserControlsState new_state,
- content::BrowserControlsState old_state,
bool animate) {
- current_browser_controls_state_ = new_state;
if (base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest))
animate = false;
- web_contents_->GetMainFrame()->UpdateBrowserControlsState(new_state,
- old_state, animate);
+ // The constraint is managed by Java code, so re-use the existing constraint
+ // and only update the desired state.
+ web_contents_->GetMainFrame()->UpdateBrowserControlsState(
+ current_browser_controls_visibility_constraint_, new_state, animate);
}
void TabImpl::CaptureScreenShot(
@@ -777,6 +807,16 @@ void TabImpl::ShowTranslateUi(JNIEnv* env) {
TranslateClientImpl::FromWebContents(web_contents())
->ManualTranslateWhenReady();
}
+
+void TabImpl::SetTranslateTargetLanguage(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jstring>& translate_target_lang) {
+ translate::TranslateManager* translate_manager =
+ TranslateClientImpl::FromWebContents(web_contents())
+ ->GetTranslateManager();
+ translate_manager->SetPredefinedTargetLanguage(
+ base::android::ConvertJavaStringToUTF8(env, translate_target_lang));
+}
#endif // OS_ANDROID
content::WebContents* TabImpl::OpenURLFromTab(
@@ -870,9 +910,26 @@ content::ColorChooser* TabImpl::OpenColorChooser(
#endif
}
+void TabImpl::CreateSmsPrompt(content::RenderFrameHost* render_frame_host,
+ const url::Origin& origin,
+ const std::string& one_time_code,
+ base::OnceClosure on_confirm,
+ base::OnceClosure on_cancel) {
+#if defined(OS_ANDROID)
+ auto* web_contents =
+ content::WebContents::FromRenderFrameHost(render_frame_host);
+ sms::SmsInfoBar::Create(
+ web_contents, InfoBarService::FromWebContents(web_contents),
+ InfoBarService::GetResourceIdMapper(), origin, one_time_code,
+ std::move(on_confirm), std::move(on_cancel));
+#else
+ NOTREACHED();
+#endif
+}
+
void TabImpl::RunFileChooser(
content::RenderFrameHost* render_frame_host,
- std::unique_ptr<content::FileSelectListener> listener,
+ scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) {
FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener),
params);
@@ -888,6 +945,16 @@ int TabImpl::GetTopControlsHeight() {
#endif
}
+int TabImpl::GetTopControlsMinHeight() {
+#if defined(OS_ANDROID)
+ return top_controls_container_view_
+ ? top_controls_container_view_->GetMinHeight()
+ : 0;
+#else
+ return 0;
+#endif
+}
+
int TabImpl::GetBottomControlsHeight() {
#if defined(OS_ANDROID)
return bottom_controls_container_view_
@@ -899,7 +966,7 @@ int TabImpl::GetBottomControlsHeight() {
}
bool TabImpl::DoBrowserControlsShrinkRendererSize(
- const content::WebContents* web_contents) {
+ content::WebContents* web_contents) {
#if defined(OS_ANDROID)
TRACE_EVENT0("weblayer", "Java_TabImpl_doBrowserControlsShrinkRendererSize");
return Java_TabImpl_doBrowserControlsShrinkRendererSize(AttachCurrentThread(),
@@ -909,6 +976,27 @@ bool TabImpl::DoBrowserControlsShrinkRendererSize(
#endif
}
+bool TabImpl::ShouldAnimateBrowserControlsHeightChanges() {
+#if defined(OS_ANDROID)
+ return top_controls_container_view_
+ ? top_controls_container_view_
+ ->ShouldAnimateBrowserControlsHeightChanges()
+ : false;
+#else
+ return false;
+#endif
+}
+
+bool TabImpl::OnlyExpandTopControlsAtPageTop() {
+#if defined(OS_ANDROID)
+ return top_controls_container_view_
+ ? top_controls_container_view_->OnlyExpandControlsAtPageTop()
+ : false;
+#else
+ return false;
+#endif
+}
+
bool TabImpl::EmbedsFullscreenWidget() {
return true;
}
@@ -1097,19 +1185,18 @@ void TabImpl::OnUpdateBrowserControlsStateBecauseOfProcessSwitch(
// This matches the logic of updateAfterRendererProcessSwitch() and
// updateEnabledState() in Chrome's TabBrowserControlsConstraintsHelper.
if (did_commit &&
- current_browser_controls_state_ ==
+ current_browser_controls_visibility_constraint_ ==
content::BROWSER_CONTROLS_STATE_SHOWN &&
top_controls_container_view_ &&
top_controls_container_view_->IsFullyVisible()) {
// The top-control is fully visible, don't animate this else the controls
// bounce around.
- UpdateBrowserControlsStateImpl(current_browser_controls_state_,
- current_browser_controls_state_, false);
+ UpdateBrowserControlsState(content::BROWSER_CONTROLS_STATE_SHOWN, false);
} else {
- UpdateBrowserControlsStateImpl(current_browser_controls_state_,
- content::BROWSER_CONTROLS_STATE_SHOWN,
- current_browser_controls_state_ !=
- content::BROWSER_CONTROLS_STATE_HIDDEN);
+ UpdateBrowserControlsState(
+ content::BROWSER_CONTROLS_STATE_BOTH,
+ current_browser_controls_visibility_constraint_ !=
+ content::BROWSER_CONTROLS_STATE_HIDDEN);
}
}
@@ -1183,10 +1270,11 @@ find_in_page::FindTabHelper* TabImpl::GetFindTabHelper() {
return find_in_page::FindTabHelper::FromWebContents(web_contents_.get());
}
+// static
sessions::SessionTabHelperDelegate* TabImpl::GetSessionServiceTabHelperDelegate(
content::WebContents* web_contents) {
- DCHECK_EQ(web_contents, web_contents_.get());
- return browser_ ? browser_->browser_persister() : nullptr;
+ TabImpl* tab = FromWebContents(web_contents);
+ return (tab && tab->browser_) ? tab->browser_->browser_persister() : nullptr;
}
bool TabImpl::SetDataInternal(const std::map<std::string, std::string>& data) {
diff --git a/chromium/weblayer/browser/tab_impl.h b/chromium/weblayer/browser/tab_impl.h
index a42739b4856..fb22911457b 100644
--- a/chromium/weblayer/browser/tab_impl.h
+++ b/chromium/weblayer/browser/tab_impl.h
@@ -99,10 +99,11 @@ class TabImpl : public Tab,
// TODO(sky): investigate a better way to not have so many ifdefs.
#if defined(OS_ANDROID)
TabImpl(ProfileImpl* profile,
- const base::android::JavaParamRef<jobject>& java_impl);
+ const base::android::JavaParamRef<jobject>& java_impl,
+ std::unique_ptr<content::WebContents> web_contents);
#endif
explicit TabImpl(ProfileImpl* profile,
- std::unique_ptr<content::WebContents> = nullptr,
+ std::unique_ptr<content::WebContents> web_contents,
const std::string& guid = std::string());
~TabImpl() override;
@@ -164,9 +165,9 @@ class TabImpl : public Tab,
void OnAutofillProviderChanged(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& autofill_provider);
- void UpdateBrowserControlsState(JNIEnv* env,
- jint raw_new_state,
- jboolean animate);
+ void UpdateBrowserControlsConstraint(JNIEnv* env,
+ jint constraint,
+ jboolean animate);
base::android::ScopedJavaLocalRef<jstring> GetGuid(JNIEnv* env);
void CaptureScreenShot(
@@ -192,6 +193,9 @@ class TabImpl : public Tab,
const base::android::JavaParamRef<jstring>& js_object_name);
jboolean CanTranslate(JNIEnv* env);
void ShowTranslateUi(JNIEnv* env);
+ void SetTranslateTargetLanguage(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jstring>& translate_target_lang);
#endif
ErrorPageDelegate* error_page_delegate() { return error_page_delegate_; }
@@ -199,10 +203,15 @@ class TabImpl : public Tab,
void AddDataObserver(DataObserver* observer);
void RemoveDataObserver(DataObserver* observer);
+ GoogleAccountsDelegate* google_accounts_delegate() {
+ return google_accounts_delegate_;
+ }
+
// Tab:
void SetErrorPageDelegate(ErrorPageDelegate* delegate) override;
void SetFullscreenDelegate(FullscreenDelegate* delegate) override;
void SetNewTabDelegate(NewTabDelegate* delegate) override;
+ void SetGoogleAccountsDelegate(GoogleAccountsDelegate* delegate) override;
void AddObserver(TabObserver* observer) override;
void RemoveObserver(TabObserver* observer) override;
NavigationController* GetNavigationController() override;
@@ -218,6 +227,8 @@ class TabImpl : public Tab,
const std::vector<std::string>& js_origins) override;
void RemoveWebMessageHostFactory(
const base::string16& js_object_name) override;
+ std::unique_ptr<FaviconFetcher> CreateFaviconFetcher(
+ FaviconFetcherDelegate* delegate) override;
#if !defined(OS_ANDROID)
void AttachToView(views::WebView* web_view) override;
#endif
@@ -248,12 +259,20 @@ class TabImpl : public Tab,
const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions)
override;
void RunFileChooser(content::RenderFrameHost* render_frame_host,
- std::unique_ptr<content::FileSelectListener> listener,
+ scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) override;
+ void CreateSmsPrompt(content::RenderFrameHost*,
+ const url::Origin&,
+ const std::string& one_time_code,
+ base::OnceClosure on_confirm,
+ base::OnceClosure on_cancel) override;
int GetTopControlsHeight() override;
+ int GetTopControlsMinHeight() override;
int GetBottomControlsHeight() override;
bool DoBrowserControlsShrinkRendererSize(
- const content::WebContents* web_contents) override;
+ content::WebContents* web_contents) override;
+ bool OnlyExpandTopControlsAtPageTop() override;
+ bool ShouldAnimateBrowserControlsHeightChanges() override;
bool EmbedsFullscreenWidget() override;
void RequestMediaAccessPermission(
content::WebContents* web_contents,
@@ -299,9 +318,8 @@ class TabImpl : public Tab,
gfx::Rect* src_rect,
gfx::Size* output_size);
- void UpdateBrowserControlsStateImpl(content::BrowserControlsState new_state,
- content::BrowserControlsState old_state,
- bool animate);
+ void UpdateBrowserControlsState(content::BrowserControlsState new_state,
+ bool animate);
#endif
// content::WebContentsObserver:
@@ -330,7 +348,7 @@ class TabImpl : public Tab,
// Returns the FindTabHelper for the page, or null if none exists.
find_in_page::FindTabHelper* GetFindTabHelper();
- sessions::SessionTabHelperDelegate* GetSessionServiceTabHelperDelegate(
+ static sessions::SessionTabHelperDelegate* GetSessionServiceTabHelperDelegate(
content::WebContents* web_contents);
#if defined(OS_ANDROID)
@@ -346,6 +364,7 @@ class TabImpl : public Tab,
ErrorPageDelegate* error_page_delegate_ = nullptr;
FullscreenDelegate* fullscreen_delegate_ = nullptr;
NewTabDelegate* new_tab_delegate_ = nullptr;
+ GoogleAccountsDelegate* google_accounts_delegate_ = nullptr;
ProfileImpl* profile_;
std::unique_ptr<content::WebContents> web_contents_;
std::unique_ptr<NavigationControllerImpl> navigation_controller_;
@@ -359,9 +378,14 @@ class TabImpl : public Tab,
std::unique_ptr<BrowserControlsNavigationStateHandler>
browser_controls_navigation_state_handler_;
- // Last value supplied to UpdateBrowserControlsState().
- content::BrowserControlsState current_browser_controls_state_ =
- content::BROWSER_CONTROLS_STATE_SHOWN;
+ // Last value supplied to UpdateBrowserControlsConstraint(). This *constraint*
+ // can be SHOWN, if for example a modal dialog is forcing the controls to be
+ // visible, HIDDEN, if for example fullscreen is forcing the controls to be
+ // hidden, or BOTH, if either state is viable (e.g. during normal browsing).
+ // When BOTH, the actual current state could be showing or hidden.
+ content::BrowserControlsState
+ current_browser_controls_visibility_constraint_ =
+ content::BROWSER_CONTROLS_STATE_SHOWN;
std::map<std::string, std::unique_ptr<WebMessageHostFactoryProxy>>
js_name_to_proxy_;
diff --git a/chromium/weblayer/browser/tab_specific_content_settings_delegate.h b/chromium/weblayer/browser/tab_specific_content_settings_delegate.h
deleted file mode 100644
index 10dcf2fe26f..00000000000
--- a/chromium/weblayer/browser/tab_specific_content_settings_delegate.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2020 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 WEBLAYER_BROWSER_TAB_SPECIFIC_CONTENT_SETTINGS_DELEGATE_H_
-#define WEBLAYER_BROWSER_TAB_SPECIFIC_CONTENT_SETTINGS_DELEGATE_H_
-
-#include "components/content_settings/browser/tab_specific_content_settings.h"
-
-namespace weblayer {
-
-// Called by TabSpecificContentSettings to handle WebLayer specific logic.
-class TabSpecificContentSettingsDelegate
- : public content_settings::TabSpecificContentSettings::Delegate {
- public:
- explicit TabSpecificContentSettingsDelegate(
- content::WebContents* web_contents);
- ~TabSpecificContentSettingsDelegate() override;
- TabSpecificContentSettingsDelegate(
- const TabSpecificContentSettingsDelegate&) = delete;
- TabSpecificContentSettingsDelegate& operator=(
- const TabSpecificContentSettingsDelegate&) = delete;
-
- static void UpdateRendererContentSettingRules(
- content::RenderProcessHost* process);
-
- private:
- // TabSpecificContentSettings::Delegate:
- void UpdateLocationBar() override;
- void SetContentSettingRules(
- content::RenderProcessHost* process,
- const RendererContentSettingRules& rules) override;
- PrefService* GetPrefs() override;
- HostContentSettingsMap* GetSettingsMap() override;
- ContentSetting GetEmbargoSetting(const GURL& request_origin,
- ContentSettingsType permission) override;
- std::vector<storage::FileSystemType> GetAdditionalFileSystemTypes() override;
- browsing_data::CookieHelper::IsDeletionDisabledCallback
- GetIsDeletionDisabledCallback() override;
- bool IsMicrophoneCameraStateChanged(
- content_settings::TabSpecificContentSettings::MicrophoneCameraState
- microphone_camera_state,
- const std::string& media_stream_selected_audio_device,
- const std::string& media_stream_selected_video_device) override;
- content_settings::TabSpecificContentSettings::MicrophoneCameraState
- GetMicrophoneCameraState() override;
- void OnContentBlocked(ContentSettingsType type) override;
-
- content::WebContents* web_contents_;
-};
-
-} // namespace weblayer
-
-#endif // WEBLAYER_BROWSER_TAB_SPECIFIC_CONTENT_SETTINGS_DELEGATE_H_
diff --git a/chromium/weblayer/browser/translate_browsertest.cc b/chromium/weblayer/browser/translate_browsertest.cc
index 2824d8b91ea..4bde4c23889 100644
--- a/chromium/weblayer/browser/translate_browsertest.cc
+++ b/chromium/weblayer/browser/translate_browsertest.cc
@@ -23,11 +23,12 @@
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
+#include "components/infobars/android/infobar_android.h" // nogncheck
#include "components/infobars/core/infobar_manager.h" // nogncheck
#include "components/translate/core/browser/translate_download_manager.h"
-#include "weblayer/browser/infobar_android.h"
#include "weblayer/browser/infobar_service.h"
#include "weblayer/browser/translate_compact_infobar.h"
+#include "weblayer/shell/android/browsertests_apk/translate_test_bridge.h"
#endif
namespace weblayer {
@@ -465,7 +466,8 @@ IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, TranslateInfoBarPresentation) {
run_loop.Run();
EXPECT_EQ(1u, infobar_service->infobar_count());
- auto* infobar = static_cast<InfoBarAndroid*>(infobar_service->infobar_at(0));
+ auto* infobar =
+ static_cast<infobars::InfoBarAndroid*>(infobar_service->infobar_at(0));
EXPECT_TRUE(infobar->HasSetJavaInfoBar());
base::RunLoop run_loop2;
@@ -520,7 +522,8 @@ IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, TranslationViaInfoBar) {
// occurs.
auto* infobar =
static_cast<TranslateCompactInfoBar*>(infobar_service->infobar_at(0));
- infobar->SelectButtonForTesting(InfoBarAndroid::ActionType::ACTION_TRANSLATE);
+ TranslateTestBridge::SelectButton(
+ infobar, infobars::InfoBarAndroid::ActionType::ACTION_TRANSLATE);
WaitUntilPageTranslated(shell());
@@ -538,8 +541,9 @@ IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, TranslationViaInfoBar) {
// Revert to the source language via the Java infobar and ensure that the
// translation is undone.
- infobar->SelectButtonForTesting(
- InfoBarAndroid::ActionType::ACTION_TRANSLATE_SHOW_ORIGINAL);
+ TranslateTestBridge::SelectButton(
+ infobar,
+ infobars::InfoBarAndroid::ActionType::ACTION_TRANSLATE_SHOW_ORIGINAL);
translate_reversion_waiter->Wait();
EXPECT_EQ("fr", translate_client->GetLanguageState().current_language());
@@ -587,8 +591,9 @@ IN_PROC_BROWSER_TEST_F(TranslateBrowserTest,
auto* infobar =
static_cast<TranslateCompactInfoBar*>(infobar_service->infobar_at(0));
- infobar->ClickOverflowMenuItemForTesting(
- TranslateCompactInfoBar::OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE);
+ TranslateTestBridge::ClickOverflowMenuItem(
+ infobar,
+ TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE);
// The translate infobar should still be present.
EXPECT_EQ(1u, infobar_service->infobar_count());
@@ -657,8 +662,8 @@ IN_PROC_BROWSER_TEST_F(TranslateBrowserTest,
auto* infobar =
static_cast<TranslateCompactInfoBar*>(infobar_service->infobar_at(0));
- infobar->ClickOverflowMenuItemForTesting(
- TranslateCompactInfoBar::OverflowMenuItemId::NEVER_TRANSLATE_SITE);
+ TranslateTestBridge::ClickOverflowMenuItem(
+ infobar, TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_SITE);
// The translate infobar should still be present.
EXPECT_EQ(1u, infobar_service->infobar_count());
@@ -689,12 +694,14 @@ IN_PROC_BROWSER_TEST_F(TranslateBrowserTest,
class NeverTranslateMenuItemTranslateBrowserTest
: public TranslateBrowserTest,
public testing::WithParamInterface<
- TranslateCompactInfoBar::OverflowMenuItemId> {};
+ TranslateTestBridge::OverflowMenuItemId> {};
// Test that clicking and unclicking a never translate item ends up being a
// no-op.
-IN_PROC_BROWSER_TEST_P(NeverTranslateMenuItemTranslateBrowserTest,
- TranslateInfoBarToggleAndToggleBackNeverTranslateItem) {
+// Disabled due to flakiness on P (crbug.com/1114795).
+IN_PROC_BROWSER_TEST_P(
+ NeverTranslateMenuItemTranslateBrowserTest,
+ DISABLED_TranslateInfoBarToggleAndToggleBackNeverTranslateItem) {
auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
auto* infobar_service = InfoBarService::FromWebContents(web_contents);
@@ -725,12 +732,12 @@ IN_PROC_BROWSER_TEST_P(NeverTranslateMenuItemTranslateBrowserTest,
auto* infobar =
static_cast<TranslateCompactInfoBar*>(infobar_service->infobar_at(0));
- infobar->ClickOverflowMenuItemForTesting(GetParam());
+ TranslateTestBridge::ClickOverflowMenuItem(infobar, GetParam());
// The translate infobar should still be present.
EXPECT_EQ(1u, infobar_service->infobar_count());
- infobar->ClickOverflowMenuItemForTesting(GetParam());
+ TranslateTestBridge::ClickOverflowMenuItem(infobar, GetParam());
}
// The infobar should be shown on a new navigation to a page in the same
@@ -768,8 +775,8 @@ INSTANTIATE_TEST_SUITE_P(
All,
NeverTranslateMenuItemTranslateBrowserTest,
::testing::Values(
- TranslateCompactInfoBar::OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE,
- TranslateCompactInfoBar::OverflowMenuItemId::NEVER_TRANSLATE_SITE));
+ TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE,
+ TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_SITE));
#endif // #if defined(OS_ANDROID)
diff --git a/chromium/weblayer/browser/translate_compact_infobar.cc b/chromium/weblayer/browser/translate_compact_infobar.cc
index 7584fe4e99a..808fb81b19c 100644
--- a/chromium/weblayer/browser/translate_compact_infobar.cc
+++ b/chromium/weblayer/browser/translate_compact_infobar.cc
@@ -12,14 +12,16 @@
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/jni_weak_ref.h"
+#include "base/bind.h"
+#include "components/translate/content/android/translate_utils.h"
#include "components/translate/core/browser/translate_infobar_delegate.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/browser/browser_context.h"
+#include "weblayer/browser/android/resource_mapper.h"
#include "weblayer/browser/infobar_service.h"
#include "weblayer/browser/java/jni/TranslateCompactInfoBar_jni.h"
#include "weblayer/browser/tab_impl.h"
#include "weblayer/browser/translate_client_impl.h"
-#include "weblayer/browser/translate_utils.h"
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
@@ -33,7 +35,9 @@ const char kTranslateTabDefaultTextColor[] = "translate_tab_default_text_color";
TranslateCompactInfoBar::TranslateCompactInfoBar(
std::unique_ptr<translate::TranslateInfoBarDelegate> delegate)
- : InfoBarAndroid(std::move(delegate)), action_flags_(FLAG_NONE) {
+ : infobars::InfoBarAndroid(std::move(delegate),
+ base::BindRepeating(&MapToJavaDrawableId)),
+ action_flags_(FLAG_NONE) {
GetDelegate()->AddObserver(this);
// Flip the translate bit if auto translate is enabled.
@@ -50,11 +54,11 @@ ScopedJavaLocalRef<jobject> TranslateCompactInfoBar::CreateRenderInfoBar(
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
base::android::ScopedJavaLocalRef<jobjectArray> java_languages =
- TranslateUtils::GetJavaLanguages(env, delegate);
+ translate::TranslateUtils::GetJavaLanguages(env, delegate);
base::android::ScopedJavaLocalRef<jobjectArray> java_codes =
- TranslateUtils::GetJavaLanguageCodes(env, delegate);
+ translate::TranslateUtils::GetJavaLanguageCodes(env, delegate);
base::android::ScopedJavaLocalRef<jintArray> java_hash_codes =
- TranslateUtils::GetJavaLanguageHashCodes(env, delegate);
+ translate::TranslateUtils::GetJavaLanguageHashCodes(env, delegate);
ScopedJavaLocalRef<jstring> source_language_code =
base::android::ConvertUTF8ToJavaString(
@@ -81,7 +85,7 @@ void TranslateCompactInfoBar::ProcessButton(int action) {
return; // We're closing; don't call anything, it might access the owner.
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
- if (action == InfoBarAndroid::ACTION_TRANSLATE) {
+ if (action == infobars::InfoBarAndroid::ACTION_TRANSLATE) {
action_flags_ |= FLAG_TRANSLATE;
delegate->Translate();
if (delegate->ShouldAutoAlwaysTranslate()) {
@@ -89,17 +93,18 @@ void TranslateCompactInfoBar::ProcessButton(int action) {
Java_TranslateCompactInfoBar_setAutoAlwaysTranslate(env,
GetJavaInfoBar());
}
- } else if (action == InfoBarAndroid::ACTION_TRANSLATE_SHOW_ORIGINAL) {
+ } else if (action ==
+ infobars::InfoBarAndroid::ACTION_TRANSLATE_SHOW_ORIGINAL) {
action_flags_ |= FLAG_REVERT;
delegate->RevertWithoutClosingInfobar();
} else {
- DCHECK_EQ(InfoBarAndroid::ACTION_NONE, action);
+ DCHECK_EQ(infobars::InfoBarAndroid::ACTION_NONE, action);
}
}
void TranslateCompactInfoBar::SetJavaInfoBar(
const base::android::JavaRef<jobject>& java_info_bar) {
- InfoBarAndroid::SetJavaInfoBar(java_info_bar);
+ infobars::InfoBarAndroid::SetJavaInfoBar(java_info_bar);
JNIEnv* env = base::android::AttachCurrentThread();
Java_TranslateCompactInfoBar_setNativePtr(env, java_info_bar,
reinterpret_cast<intptr_t>(this));
@@ -111,12 +116,12 @@ void TranslateCompactInfoBar::ApplyStringTranslateOption(
int option,
const JavaParamRef<jstring>& value) {
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
- if (option == TranslateUtils::OPTION_SOURCE_CODE) {
+ if (option == translate::TranslateUtils::OPTION_SOURCE_CODE) {
std::string source_code =
base::android::ConvertJavaStringToUTF8(env, value);
if (delegate->original_language_code().compare(source_code) != 0)
delegate->UpdateOriginalLanguage(source_code);
- } else if (option == TranslateUtils::OPTION_TARGET_CODE) {
+ } else if (option == translate::TranslateUtils::OPTION_TARGET_CODE) {
std::string target_code =
base::android::ConvertJavaStringToUTF8(env, value);
if (delegate->target_language_code().compare(target_code) != 0)
@@ -132,18 +137,18 @@ void TranslateCompactInfoBar::ApplyBoolTranslateOption(
int option,
jboolean value) {
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
- if (option == TranslateUtils::OPTION_ALWAYS_TRANSLATE) {
+ if (option == translate::TranslateUtils::OPTION_ALWAYS_TRANSLATE) {
if (delegate->ShouldAlwaysTranslate() != value) {
action_flags_ |= FLAG_ALWAYS_TRANSLATE;
delegate->ToggleAlwaysTranslate();
}
- } else if (option == TranslateUtils::OPTION_NEVER_TRANSLATE) {
+ } else if (option == translate::TranslateUtils::OPTION_NEVER_TRANSLATE) {
bool language_blocklisted = !delegate->IsTranslatableLanguageByPrefs();
if (language_blocklisted != value) {
action_flags_ |= FLAG_NEVER_LANGUAGE;
delegate->ToggleTranslatableLanguageByPrefs();
}
- } else if (option == TranslateUtils::OPTION_NEVER_TRANSLATE_SITE) {
+ } else if (option == translate::TranslateUtils::OPTION_NEVER_TRANSLATE_SITE) {
if (delegate->IsSiteBlacklisted() != value) {
action_flags_ |= FLAG_NEVER_SITE;
delegate->ToggleSiteBlacklist();
@@ -200,6 +205,11 @@ translate::TranslateInfoBarDelegate* TranslateCompactInfoBar::GetDelegate() {
void TranslateCompactInfoBar::OnTranslateStepChanged(
translate::TranslateStep step,
translate::TranslateErrors::Type error_type) {
+ // If the tab lost active state while translation was occurring, the Java
+ // infobar will now be gone. In that case there is nothing to do here.
+ if (!HasSetJavaInfoBar())
+ return; // No connected Java infobar
+
if (!owner())
return; // We're closing; don't call anything.
@@ -222,25 +232,4 @@ void TranslateCompactInfoBar::OnTranslateInfoBarDelegateDestroyed(
GetDelegate()->RemoveObserver(this);
}
-void TranslateCompactInfoBar::SelectButtonForTesting(ActionType action_type) {
- JNIEnv* env = base::android::AttachCurrentThread();
- Java_TranslateCompactInfoBar_selectTabForTesting(env, GetJavaInfoBar(),
- action_type);
-}
-
-void TranslateCompactInfoBar::ClickOverflowMenuItemForTesting(
- OverflowMenuItemId item_id) {
- JNIEnv* env = base::android::AttachCurrentThread();
- switch (item_id) {
- case OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE:
- Java_TranslateCompactInfoBar_clickNeverTranslateLanguageMenuItemForTesting(
- env, GetJavaInfoBar());
- return;
- case OverflowMenuItemId::NEVER_TRANSLATE_SITE:
- Java_TranslateCompactInfoBar_clickNeverTranslateSiteMenuItemForTesting(
- env, GetJavaInfoBar());
- return;
- }
-}
-
} // namespace weblayer
diff --git a/chromium/weblayer/browser/translate_compact_infobar.h b/chromium/weblayer/browser/translate_compact_infobar.h
index d4cfc20c3fd..2e85f5ba2d1 100644
--- a/chromium/weblayer/browser/translate_compact_infobar.h
+++ b/chromium/weblayer/browser/translate_compact_infobar.h
@@ -7,10 +7,10 @@
#include "base/android/scoped_java_ref.h"
#include "base/macros.h"
+#include "components/infobars/android/infobar_android.h"
#include "components/translate/core/browser/translate_infobar_delegate.h"
#include "components/translate/core/browser/translate_step.h"
#include "components/translate/core/common/translate_errors.h"
-#include "weblayer/browser/infobar_android.h"
namespace translate {
class TranslateInfoBarDelegate;
@@ -19,18 +19,13 @@ class TranslateInfoBarDelegate;
namespace weblayer {
class TranslateCompactInfoBar
- : public InfoBarAndroid,
+ : public infobars::InfoBarAndroid,
public translate::TranslateInfoBarDelegate::Observer {
public:
explicit TranslateCompactInfoBar(
std::unique_ptr<translate::TranslateInfoBarDelegate> delegate);
~TranslateCompactInfoBar() override;
- enum class OverflowMenuItemId {
- NEVER_TRANSLATE_LANGUAGE = 0,
- NEVER_TRANSLATE_SITE = 1,
- };
-
// JNI method specific to string settings in translate.
void ApplyStringTranslateOption(
JNIEnv* env,
@@ -65,15 +60,8 @@ class TranslateCompactInfoBar
void OnTranslateInfoBarDelegateDestroyed(
translate::TranslateInfoBarDelegate* delegate) override;
- // Instructs the Java infobar to select the button corresponding to
- // |action_type|.
- void SelectButtonForTesting(ActionType action_type);
-
- // Instructs the Java infobar to click the specified overflow menu item.
- void ClickOverflowMenuItemForTesting(OverflowMenuItemId item_id);
-
private:
- // InfoBarAndroid:
+ // infobars::InfoBarAndroid:
base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
JNIEnv* env) override;
void ProcessButton(int action) override;
diff --git a/chromium/weblayer/browser/translate_utils.cc b/chromium/weblayer/browser/translate_utils.cc
deleted file mode 100644
index aac744a115e..00000000000
--- a/chromium/weblayer/browser/translate_utils.cc
+++ /dev/null
@@ -1,54 +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 "weblayer/browser/translate_utils.h"
-
-#include <stddef.h>
-
-#include "base/android/jni_array.h"
-#include "base/android/jni_string.h"
-#include "base/android/jni_weak_ref.h"
-#include "components/metrics/metrics_log.h"
-#include "components/translate/core/browser/translate_infobar_delegate.h"
-
-using base::android::JavaParamRef;
-using base::android::ScopedJavaLocalRef;
-
-namespace weblayer {
-
-ScopedJavaLocalRef<jobjectArray> TranslateUtils::GetJavaLanguages(
- JNIEnv* env,
- translate::TranslateInfoBarDelegate* delegate) {
- std::vector<base::string16> languages;
- languages.reserve(delegate->num_languages());
- for (size_t i = 0; i < delegate->num_languages(); ++i) {
- languages.push_back(delegate->language_name_at(i));
- }
- return base::android::ToJavaArrayOfStrings(env, languages);
-}
-
-ScopedJavaLocalRef<jobjectArray> TranslateUtils::GetJavaLanguageCodes(
- JNIEnv* env,
- translate::TranslateInfoBarDelegate* delegate) {
- std::vector<std::string> codes;
- codes.reserve(delegate->num_languages());
- for (size_t i = 0; i < delegate->num_languages(); ++i) {
- codes.push_back(delegate->language_code_at(i));
- }
- return base::android::ToJavaArrayOfStrings(env, codes);
-}
-
-ScopedJavaLocalRef<jintArray> TranslateUtils::GetJavaLanguageHashCodes(
- JNIEnv* env,
- translate::TranslateInfoBarDelegate* delegate) {
- std::vector<int> hashCodes;
- hashCodes.reserve(delegate->num_languages());
- for (size_t i = 0; i < delegate->num_languages(); ++i) {
- hashCodes.push_back(
- metrics::MetricsLog::Hash(delegate->language_code_at(i)));
- }
- return base::android::ToJavaIntArray(env, hashCodes);
-}
-
-} // namespace weblayer
diff --git a/chromium/weblayer/browser/translate_utils.h b/chromium/weblayer/browser/translate_utils.h
deleted file mode 100644
index 9bee56b5d7a..00000000000
--- a/chromium/weblayer/browser/translate_utils.h
+++ /dev/null
@@ -1,43 +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 WEBLAYER_BROWSER_TRANSLATE_UTILS_H_
-#define WEBLAYER_BROWSER_TRANSLATE_UTILS_H_
-
-#include "base/android/jni_android.h"
-#include "base/android/scoped_java_ref.h"
-
-namespace translate {
-class TranslateInfoBarDelegate;
-}
-
-namespace weblayer {
-
-class TranslateUtils {
- public:
- // A Java counterpart will be generated for this enum.
- // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.weblayer_private
- // GENERATED_JAVA_PREFIX_TO_STRIP:OPTION_
- enum TranslateOption {
- OPTION_SOURCE_CODE,
- OPTION_TARGET_CODE,
- OPTION_ALWAYS_TRANSLATE,
- OPTION_NEVER_TRANSLATE,
- OPTION_NEVER_TRANSLATE_SITE
- };
-
- static base::android::ScopedJavaLocalRef<jobjectArray> GetJavaLanguages(
- JNIEnv* env,
- translate::TranslateInfoBarDelegate* delegate);
- static base::android::ScopedJavaLocalRef<jobjectArray> GetJavaLanguageCodes(
- JNIEnv* env,
- translate::TranslateInfoBarDelegate* delegate);
- static base::android::ScopedJavaLocalRef<jintArray> GetJavaLanguageHashCodes(
- JNIEnv* env,
- translate::TranslateInfoBarDelegate* delegate);
-};
-
-} // namespace weblayer
-
-#endif // WEBLAYER_BROWSER_TRANSLATE_UTILS_H_
diff --git a/chromium/weblayer/browser/tts_environment_android_impl.cc b/chromium/weblayer/browser/tts_environment_android_impl.cc
new file mode 100644
index 00000000000..cc69d87c904
--- /dev/null
+++ b/chromium/weblayer/browser/tts_environment_android_impl.cc
@@ -0,0 +1,36 @@
+// Copyright 2020 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 "weblayer/browser/tts_environment_android_impl.h"
+
+#include "base/callback.h"
+
+namespace weblayer {
+
+TtsEnvironmentAndroidImpl::TtsEnvironmentAndroidImpl() = default;
+
+TtsEnvironmentAndroidImpl::~TtsEnvironmentAndroidImpl() = default;
+
+bool TtsEnvironmentAndroidImpl::CanSpeakUtterancesFromHiddenWebContents() {
+ // For simplicity's sake, disallow playing utterances in hidden WebContents.
+ // Other options are to allow this, and instead cancel any utterances when
+ // all browsers are paused.
+ return false;
+}
+
+bool TtsEnvironmentAndroidImpl::CanSpeakNow() {
+ // Always return true, as by the time we get here we know the WebContents
+ // is visible (because CanSpeakUtterancesFromHiddenWebContents() returns
+ // false). Further, when the fragment is paused/stopped the WebContents is
+ // hidden, which triggers the utterance to stop (because
+ // CanSpeakUtterancesFromHiddenWebContents() returns false).
+ return true;
+}
+
+void TtsEnvironmentAndroidImpl::SetCanSpeakNowChangedCallback(
+ base::RepeatingClosure callback) {
+ // As CanSpeakNow() always returns true, there is nothing to do here.
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/tts_environment_android_impl.h b/chromium/weblayer/browser/tts_environment_android_impl.h
new file mode 100644
index 00000000000..9cca9408ddc
--- /dev/null
+++ b/chromium/weblayer/browser/tts_environment_android_impl.h
@@ -0,0 +1,30 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_TTS_ENVIRONMENT_ANDROID_IMPL_H_
+#define WEBLAYER_BROWSER_TTS_ENVIRONMENT_ANDROID_IMPL_H_
+
+#include "content/public/browser/tts_environment_android.h"
+
+namespace weblayer {
+
+// WebLayer implementation of TtsEnvironmentAndroid. This does not allow
+// speech from hidden WebContents.
+class TtsEnvironmentAndroidImpl : public content::TtsEnvironmentAndroid {
+ public:
+ TtsEnvironmentAndroidImpl();
+ TtsEnvironmentAndroidImpl(const TtsEnvironmentAndroidImpl&) = delete;
+ TtsEnvironmentAndroidImpl& operator=(const TtsEnvironmentAndroidImpl&) =
+ delete;
+ ~TtsEnvironmentAndroidImpl() override;
+
+ // TtsEnvironment:
+ bool CanSpeakUtterancesFromHiddenWebContents() override;
+ bool CanSpeakNow() override;
+ void SetCanSpeakNowChangedCallback(base::RepeatingClosure callback) override;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_TTS_ENVIRONMENT_ANDROID_IMPL_H_
diff --git a/chromium/weblayer/browser/ukm_page_load_metrics_observer.cc b/chromium/weblayer/browser/ukm_page_load_metrics_observer.cc
new file mode 100644
index 00000000000..d84009acbd9
--- /dev/null
+++ b/chromium/weblayer/browser/ukm_page_load_metrics_observer.cc
@@ -0,0 +1,41 @@
+// Copyright 2020 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 "weblayer/browser/ukm_page_load_metrics_observer.h"
+
+#include "build/build_config.h"
+#include "components/prerender/browser/prerender_manager.h"
+#include "components/prerender/browser/prerender_util.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h"
+
+namespace weblayer {
+
+// static
+std::unique_ptr<page_load_metrics::PageLoadMetricsObserver>
+UkmPageLoadMetricsObserver::CreateIfNeeded() {
+ if (!ukm::UkmRecorder::Get()) {
+ return nullptr;
+ }
+ return std::make_unique<UkmPageLoadMetricsObserver>();
+}
+
+UkmPageLoadMetricsObserver::ObservePolicy UkmPageLoadMetricsObserver::OnCommit(
+ content::NavigationHandle* navigation_handle,
+ ukm::SourceId source_id) {
+#if defined(OS_ANDROID)
+ prerender::PrerenderManager* const prerender_manager =
+ PrerenderManagerFactory::GetForBrowserContext(
+ navigation_handle->GetWebContents()->GetBrowserContext());
+ if (!prerender_manager)
+ return CONTINUE_OBSERVING;
+ prerender::RecordNoStatePrefetchMetrics(navigation_handle, source_id,
+ prerender_manager);
+#endif
+ return CONTINUE_OBSERVING;
+}
+
+} // namespace weblayer
diff --git a/chromium/weblayer/browser/ukm_page_load_metrics_observer.h b/chromium/weblayer/browser/ukm_page_load_metrics_observer.h
new file mode 100644
index 00000000000..30e17b39c87
--- /dev/null
+++ b/chromium/weblayer/browser/ukm_page_load_metrics_observer.h
@@ -0,0 +1,35 @@
+// Copyright 2020 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 WEBLAYER_BROWSER_UKM_PAGE_LOAD_METRICS_OBSERVER_H_
+#define WEBLAYER_BROWSER_UKM_PAGE_LOAD_METRICS_OBSERVER_H_
+
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+
+namespace content {
+class NavigationHandle;
+}
+
+namespace weblayer {
+
+// If URL-Keyed-Metrics (UKM) is enabled in the system, this is used to
+// populate it with top-level page-load metrics.
+class UkmPageLoadMetricsObserver
+ : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+ // Returns a UkmPageLoadMetricsObserver, or nullptr if it is not needed.
+ static std::unique_ptr<page_load_metrics::PageLoadMetricsObserver>
+ CreateIfNeeded();
+
+ UkmPageLoadMetricsObserver() = default;
+ ~UkmPageLoadMetricsObserver() override = default;
+
+ // page_load_metrics::PageLoadMetricsObserver implementation:
+ ObservePolicy OnCommit(content::NavigationHandle* navigation_handle,
+ ukm::SourceId source_id) override;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_BROWSER_UKM_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chromium/weblayer/browser/url_bar/page_info_browsertest.cc b/chromium/weblayer/browser/url_bar/page_info_browsertest.cc
index dc4ad642678..6c5971995ab 100644
--- a/chromium/weblayer/browser/url_bar/page_info_browsertest.cc
+++ b/chromium/weblayer/browser/url_bar/page_info_browsertest.cc
@@ -76,11 +76,11 @@ IN_PROC_BROWSER_TEST_F(PageInfoBrowserTest, PermissionStatus) {
}
IN_PROC_BROWSER_TEST_F(PageInfoBrowserTest,
- TabSpecificContentSettingsDelegate) {
+ PageSpecificContentSettingsDelegate) {
std::unique_ptr<PageInfoDelegate> page_info_delegate =
page_info::GetPageInfoClient()->CreatePageInfoDelegate(GetWebContents());
ASSERT_TRUE(page_info_delegate);
- EXPECT_TRUE(page_info_delegate->GetTabSpecificContentSettingsDelegate());
+ EXPECT_TRUE(page_info_delegate->GetPageSpecificContentSettingsDelegate());
}
IN_PROC_BROWSER_TEST_F(PageInfoBrowserTest, EmbedderNameSet) {
diff --git a/chromium/weblayer/browser/url_bar/page_info_delegate_impl.cc b/chromium/weblayer/browser/url_bar/page_info_delegate_impl.cc
index f189430f4d0..e79597f6860 100644
--- a/chromium/weblayer/browser/url_bar/page_info_delegate_impl.cc
+++ b/chromium/weblayer/browser/url_bar/page_info_delegate_impl.cc
@@ -10,10 +10,10 @@
#include "components/security_state/content/content_utils.h"
#include "content/public/browser/browser_context.h"
#include "weblayer/browser/host_content_settings_map_factory.h"
+#include "weblayer/browser/page_specific_content_settings_delegate.h"
#include "weblayer/browser/permissions/permission_decision_auto_blocker_factory.h"
#include "weblayer/browser/permissions/permission_manager_factory.h"
#include "weblayer/browser/stateful_ssl_host_state_delegate_factory.h"
-#include "weblayer/browser/tab_specific_content_settings_delegate.h"
#if defined(OS_ANDROID)
#include "weblayer/browser/weblayer_impl_android.h"
@@ -90,6 +90,15 @@ HostContentSettingsMap* PageInfoDelegateImpl::GetContentSettings() {
GetBrowserContext());
}
+bool PageInfoDelegateImpl::IsSubresourceFilterActivated(const GURL& site_url) {
+ // As the WebLayer does not support subresource filtering, a site
+ // will not have ads blocked as a result of this setting. Return false
+ // so we do not show the ad blocking permission.
+ // TODO(https://crbug.com/1116095): Add subresource filtering to the
+ // WebLayer.
+ return false;
+}
+
bool PageInfoDelegateImpl::IsContentDisplayedInVrHeadset() {
// VR is not supported for WebLayer.
return false;
@@ -108,9 +117,9 @@ PageInfoDelegateImpl::GetVisibleSecurityState() {
return *security_state::GetVisibleSecurityState(web_contents_);
}
-std::unique_ptr<content_settings::TabSpecificContentSettings::Delegate>
-PageInfoDelegateImpl::GetTabSpecificContentSettingsDelegate() {
- return std::make_unique<TabSpecificContentSettingsDelegate>(web_contents_);
+std::unique_ptr<content_settings::PageSpecificContentSettings::Delegate>
+PageInfoDelegateImpl::GetPageSpecificContentSettingsDelegate() {
+ return std::make_unique<PageSpecificContentSettingsDelegate>(web_contents_);
}
#if defined(OS_ANDROID)
diff --git a/chromium/weblayer/browser/url_bar/page_info_delegate_impl.h b/chromium/weblayer/browser/url_bar/page_info_delegate_impl.h
index 65939b39072..5d7ce4e1c87 100644
--- a/chromium/weblayer/browser/url_bar/page_info_delegate_impl.h
+++ b/chromium/weblayer/browser/url_bar/page_info_delegate_impl.h
@@ -43,8 +43,9 @@ class PageInfoDelegateImpl : public PageInfoDelegate {
override;
StatefulSSLHostStateDelegate* GetStatefulSSLHostStateDelegate() override;
HostContentSettingsMap* GetContentSettings() override;
- std::unique_ptr<content_settings::TabSpecificContentSettings::Delegate>
- GetTabSpecificContentSettingsDelegate() override;
+ std::unique_ptr<content_settings::PageSpecificContentSettings::Delegate>
+ GetPageSpecificContentSettingsDelegate() override;
+ bool IsSubresourceFilterActivated(const GURL& site_url) override;
bool IsContentDisplayedInVrHeadset() override;
security_state::SecurityLevel GetSecurityLevel() override;
security_state::VisibleSecurityState GetVisibleSecurityState() override;
diff --git a/chromium/weblayer/browser/url_bar/url_bar_controller_impl.h b/chromium/weblayer/browser/url_bar/url_bar_controller_impl.h
index dacd8077746..3e564133d95 100644
--- a/chromium/weblayer/browser/url_bar/url_bar_controller_impl.h
+++ b/chromium/weblayer/browser/url_bar/url_bar_controller_impl.h
@@ -8,13 +8,14 @@
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "components/omnibox/browser/location_bar_model_delegate.h"
-#include "components/omnibox/browser/location_bar_model_impl.h"
#include "weblayer/public/url_bar_controller.h"
#if defined(OS_ANDROID)
#include "base/android/scoped_java_ref.h"
#endif
+class LocationBarModelImpl;
+
namespace content {
class WebContents;
}
diff --git a/chromium/weblayer/browser/weblayer_browser_interface_binders.cc b/chromium/weblayer/browser/weblayer_browser_interface_binders.cc
index a0043214a7e..5813a0cb3de 100644
--- a/chromium/weblayer/browser/weblayer_browser_interface_binders.cc
+++ b/chromium/weblayer/browser/weblayer_browser_interface_binders.cc
@@ -6,6 +6,9 @@
#include "base/bind.h"
#include "build/build_config.h"
+#include "components/prerender/browser/prerender_contents.h"
+#include "components/prerender/browser/prerender_processor_impl.h"
+#include "components/prerender/common/prerender_canceler.mojom.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
@@ -13,6 +16,9 @@
#include "content/public/browser/web_ui_controller.h"
#include "third_party/blink/public/mojom/installedapp/installed_app_provider.mojom.h"
#include "third_party/blink/public/mojom/installedapp/related_application.mojom.h"
+#include "third_party/blink/public/mojom/prerender/prerender.mojom.h"
+#include "weblayer/browser/no_state_prefetch/prerender_processor_impl_delegate_impl.h"
+#include "weblayer/browser/no_state_prefetch/prerender_utils.h"
#include "weblayer/browser/translate_client_impl.h"
#include "weblayer/browser/webui/weblayer_internals.mojom.h"
#include "weblayer/browser/webui/weblayer_internals_ui.h"
@@ -65,6 +71,27 @@ void BindPageHandler(
concrete_controller->BindInterface(std::move(receiver));
}
+void BindPrerenderProcessor(
+ content::RenderFrameHost* frame_host,
+ mojo::PendingReceiver<blink::mojom::PrerenderProcessor> receiver) {
+ prerender::PrerenderProcessorImpl::Create(
+ frame_host, std::move(receiver),
+ std::make_unique<PrerenderProcessorImplDelegateImpl>());
+}
+
+void BindPrerenderCanceler(
+ content::RenderFrameHost* frame_host,
+ mojo::PendingReceiver<prerender::mojom::PrerenderCanceler> receiver) {
+ auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host);
+ if (!web_contents)
+ return;
+
+ auto* prerender_contents = PrerenderContentsFromWebContents(web_contents);
+ if (!prerender_contents)
+ return;
+ prerender_contents->AddPrerenderCancelerReceiver(std::move(receiver));
+}
+
#if defined(OS_ANDROID)
// TODO(https://crbug.com/1037884): Remove this.
class StubInstalledAppProvider : public blink::mojom::InstalledAppProvider {
@@ -109,6 +136,11 @@ void PopulateWebLayerFrameBinders(
map->Add<translate::mojom::ContentTranslateDriver>(
base::BindRepeating(&BindContentTranslateDriver));
+ map->Add<blink::mojom::PrerenderProcessor>(
+ base::BindRepeating(&BindPrerenderProcessor));
+ map->Add<prerender::mojom::PrerenderCanceler>(
+ base::BindRepeating(&BindPrerenderCanceler));
+
#if defined(OS_ANDROID)
// TODO(https://crbug.com/1037884): Remove this.
map->Add<blink::mojom::InstalledAppProvider>(
diff --git a/chromium/weblayer/browser/weblayer_content_browser_overlay_manifest.cc b/chromium/weblayer/browser/weblayer_content_browser_overlay_manifest.cc
deleted file mode 100644
index c121bc83b10..00000000000
--- a/chromium/weblayer/browser/weblayer_content_browser_overlay_manifest.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "weblayer/browser/weblayer_content_browser_overlay_manifest.h"
-
-#include "base/no_destructor.h"
-#include "services/service_manager/public/cpp/manifest_builder.h"
-
-namespace weblayer {
-
-const service_manager::Manifest& GetWebLayerContentBrowserOverlayManifest() {
- static base::NoDestructor<service_manager::Manifest> manifest{
- service_manager::ManifestBuilder()
- .Build()};
- return *manifest;
-}
-
-} // namespace weblayer
diff --git a/chromium/weblayer/browser/weblayer_content_browser_overlay_manifest.h b/chromium/weblayer/browser/weblayer_content_browser_overlay_manifest.h
deleted file mode 100644
index e4ed36670f5..00000000000
--- a/chromium/weblayer/browser/weblayer_content_browser_overlay_manifest.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WEBLAYER_BROWSER_WEBLAYER_CONTENT_BROWSER_OVERLAY_MANIFEST_H_
-#define WEBLAYER_BROWSER_WEBLAYER_CONTENT_BROWSER_OVERLAY_MANIFEST_H_
-
-#include "services/service_manager/public/cpp/manifest.h"
-
-namespace weblayer {
-
-// Returns the manifest WebLayer amends to Content's content_browser service
-// manifest. This allows WebLayer to extend the capabilities exposed and/or
-// required by content_browser service instances, as well as declaring any
-// additional in- and out-of-process per-profile packaged services.
-const service_manager::Manifest& GetWebLayerContentBrowserOverlayManifest();
-
-} // namespace weblayer
-
-#endif // WEBLAYER_BROWSER_WEBLAYER_CONTENT_BROWSER_OVERLAY_MANIFEST_H_
diff --git a/chromium/weblayer/browser/weblayer_impl_android.cc b/chromium/weblayer/browser/weblayer_impl_android.cc
index d07dc34ef0e..478f127a721 100644
--- a/chromium/weblayer/browser/weblayer_impl_android.cc
+++ b/chromium/weblayer/browser/weblayer_impl_android.cc
@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "weblayer/browser/weblayer_impl_android.h"
+
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "components/crash/core/common/crash_key.h"
#include "components/page_info/android/page_info_client.h"
#include "weblayer/browser/android/metrics/weblayer_metrics_service_client.h"
+#include "weblayer/browser/default_search_engine.h"
#include "weblayer/browser/devtools_server_android.h"
#include "weblayer/browser/java/jni/WebLayerImpl_jni.h"
#include "weblayer/browser/url_bar/page_info_client_impl.h"
@@ -63,4 +65,12 @@ base::string16 GetClientApplicationName() {
env, Java_WebLayerImpl_getEmbedderName(env));
}
+static jboolean JNI_WebLayerImpl_IsLocationPermissionManaged(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jstring>& origin) {
+ return IsPermissionControlledByDse(
+ ContentSettingsType::GEOLOCATION,
+ url::Origin::Create(GURL(ConvertJavaStringToUTF8(origin))));
+}
+
} // namespace weblayer
diff --git a/chromium/weblayer/browser/weblayer_security_blocking_page_factory.cc b/chromium/weblayer/browser/weblayer_security_blocking_page_factory.cc
index 37d3676f4f0..b7e9703840f 100644
--- a/chromium/weblayer/browser/weblayer_security_blocking_page_factory.cc
+++ b/chromium/weblayer/browser/weblayer_security_blocking_page_factory.cc
@@ -6,10 +6,12 @@
#include "components/captive_portal/core/buildflags.h"
#include "components/security_interstitials/content/content_metrics_helper.h"
+#include "components/security_interstitials/content/insecure_form_blocking_page.h"
#include "components/security_interstitials/content/ssl_blocking_page.h"
#include "components/security_interstitials/core/metrics_helper.h"
#include "content/public/browser/web_contents.h"
#include "weblayer/browser/captive_portal_service_factory.h"
+#include "weblayer/browser/insecure_form_controller_client.h"
#include "weblayer/browser/ssl_error_controller_client.h"
#if defined(OS_ANDROID)
@@ -201,10 +203,12 @@ std::unique_ptr<security_interstitials::InsecureFormBlockingPage>
WebLayerSecurityBlockingPageFactory::CreateInsecureFormBlockingPage(
content::WebContents* web_contents,
const GURL& request_url) {
- // TODO(crbug.com/1093102): Insecure form warnings are not yet implemented in
- // Weblayer.
- NOTREACHED();
- return nullptr;
+ std::unique_ptr<InsecureFormControllerClient> client =
+ std::make_unique<InsecureFormControllerClient>(web_contents, request_url);
+ auto page =
+ std::make_unique<security_interstitials::InsecureFormBlockingPage>(
+ web_contents, request_url, std::move(client));
+ return page;
}
#if defined(OS_ANDROID)
diff --git a/chromium/weblayer/browser/weblayer_variations_http_browsertest.cc b/chromium/weblayer/browser/weblayer_variations_http_browsertest.cc
index f55317daf82..6db7051cdef 100644
--- a/chromium/weblayer/browser/weblayer_variations_http_browsertest.cc
+++ b/chromium/weblayer/browser/weblayer_variations_http_browsertest.cc
@@ -4,7 +4,7 @@
#include "weblayer/test/weblayer_browser_test.h"
-#include "components/variations/variations_http_header_provider.h"
+#include "components/variations/variations_ids_provider.h"
#include "content/public/test/network_connection_change_simulator.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
@@ -12,59 +12,11 @@
#include "net/test/embedded_test_server/http_response.h"
#include "weblayer/public/navigation.h"
#include "weblayer/public/navigation_controller.h"
-#include "weblayer/public/navigation_observer.h"
#include "weblayer/public/tab.h"
#include "weblayer/shell/browser/shell.h"
#include "weblayer/test/weblayer_browser_test_utils.h"
namespace weblayer {
-namespace {
-
-class OneShotNavigationObserver : public NavigationObserver {
- public:
- explicit OneShotNavigationObserver(Shell* shell) : tab_(shell->tab()) {
- tab_->GetNavigationController()->AddObserver(this);
- }
-
- ~OneShotNavigationObserver() override {
- tab_->GetNavigationController()->RemoveObserver(this);
- }
-
- void WaitForNavigation() { run_loop_.Run(); }
-
- bool completed() { return completed_; }
- bool is_error_page() { return is_error_page_; }
- Navigation::LoadError load_error() { return load_error_; }
- int http_status_code() { return http_status_code_; }
- NavigationState navigation_state() { return navigation_state_; }
-
- private:
- // NavigationObserver implementation:
- void NavigationCompleted(Navigation* navigation) override {
- completed_ = true;
- Finish(navigation);
- }
-
- void NavigationFailed(Navigation* navigation) override { Finish(navigation); }
-
- void Finish(Navigation* navigation) {
- is_error_page_ = navigation->IsErrorPage();
- load_error_ = navigation->GetLoadError();
- http_status_code_ = navigation->GetHttpStatusCode();
- navigation_state_ = navigation->GetState();
- run_loop_.Quit();
- }
-
- base::RunLoop run_loop_;
- Tab* tab_;
- bool completed_ = false;
- bool is_error_page_ = false;
- Navigation::LoadError load_error_ = Navigation::kNoError;
- int http_status_code_ = 0;
- NavigationState navigation_state_ = NavigationState::kWaitingResponse;
-};
-
-} // namespace
// The purpose of this test is to verify Variations code is correctly wired up
// for WebLayer. It's not intended to replicate VariationsHttpHeadersBrowserTest
@@ -87,7 +39,7 @@ class WebLayerVariationsHttpBrowserTest : public WebLayerBrowserTest {
void SetUpOnMainThread() override {
auto* variations_provider =
- variations::VariationsHttpHeaderProvider::GetInstance();
+ variations::VariationsIdsProvider::GetInstance();
variations_provider->ForceVariationIds({"12", "456", "t789"}, "");
// The test makes requests to google.com which we want to redirect to the